diff options
author | Dave Lerner <dave.lerner@windriver.com> | 2016-03-24 12:12:11 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-03-26 07:34:58 +0000 |
commit | b036afb53783d8600e505ee5a480a8a9f89a0403 (patch) | |
tree | 0961de2ff506cb0ed6e7228bfd03db38915bb588 | |
parent | 9bf98a935177ce7ac04c830bcecbfc22961c36b8 (diff) | |
download | poky-b036afb53783d8600e505ee5a480a8a9f89a0403.tar.gz |
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>
-rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 91 |
1 files changed, 79 insertions, 12 deletions
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 15760b36de..cc7ad17cf1 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -2538,6 +2538,60 @@ if True: | |||
2538 | 2538 | ||
2539 | return response | 2539 | return response |
2540 | 2540 | ||
2541 | def _traverse_dependents(next_package_id, rev_deps, all_current_packages, tree_level=0): | ||
2542 | """ | ||
2543 | Recurse through reverse dependency tree for next_package_id. | ||
2544 | Limit the reverse dependency search to packages not already scanned, | ||
2545 | that is, not already in rev_deps. | ||
2546 | Limit the scan to a depth (tree_level) not exceeding the count of | ||
2547 | all packages in the custom image, and if that depth is exceeded | ||
2548 | return False, pop out of the recursion, and write a warning | ||
2549 | to the log, but this is unlikely, suggesting a dependency loop | ||
2550 | not caught by bitbake. | ||
2551 | On return, the input/output arg rev_deps is appended with queryset | ||
2552 | dictionary elements, annotated for use in the customimage template. | ||
2553 | The list has unsorted, but unique elements. | ||
2554 | """ | ||
2555 | max_dependency_tree_depth = all_current_packages.count() | ||
2556 | if tree_level >= max_dependency_tree_depth: | ||
2557 | logger.warning( | ||
2558 | "The number of reverse dependencies " | ||
2559 | "for this package exceeds " + max_dependency_tree_depth + | ||
2560 | " and the remaining reverse dependencies will not be removed") | ||
2561 | return True | ||
2562 | |||
2563 | package = CustomImagePackage.objects.get(id=next_package_id) | ||
2564 | dependents = \ | ||
2565 | package.package_dependencies_target.annotate( | ||
2566 | name=F('package__name'), | ||
2567 | pk=F('package__pk'), | ||
2568 | size=F('package__size'), | ||
2569 | ).values("name", "pk", "size").exclude( | ||
2570 | ~Q(pk__in=all_current_packages) | ||
2571 | ) | ||
2572 | |||
2573 | for pkg in dependents: | ||
2574 | if pkg in rev_deps: | ||
2575 | # already seen, skip dependent search | ||
2576 | continue | ||
2577 | |||
2578 | rev_deps.append(pkg) | ||
2579 | if (_traverse_dependents( | ||
2580 | pkg["pk"], rev_deps, all_current_packages, tree_level+1)): | ||
2581 | return True | ||
2582 | |||
2583 | return False | ||
2584 | |||
2585 | def _get_all_dependents(package_id, all_current_packages): | ||
2586 | """ | ||
2587 | Returns sorted list of recursive reverse dependencies for package_id, | ||
2588 | as a list of dictionary items, by recursing through dependency | ||
2589 | relationships. | ||
2590 | """ | ||
2591 | rev_deps = [] | ||
2592 | _traverse_dependents(package_id, rev_deps, all_current_packages) | ||
2593 | rev_deps = sorted(rev_deps, key=lambda x: x["name"]) | ||
2594 | return rev_deps | ||
2541 | 2595 | ||
2542 | @xhr_response | 2596 | @xhr_response |
2543 | def xhr_customrecipe_packages(request, recipe_id, package_id): | 2597 | def xhr_customrecipe_packages(request, recipe_id, package_id): |
@@ -2606,15 +2660,9 @@ if True: | |||
2606 | ) | 2660 | ) |
2607 | 2661 | ||
2608 | # Reverse dependencies which are needed by packages that are | 2662 | # Reverse dependencies which are needed by packages that are |
2609 | # in the image | 2663 | # in the image. Recursive search providing all dependents, |
2610 | reverse_deps = package.package_dependencies_target.annotate( | 2664 | # not just immediate dependents. |
2611 | name=F('package__name'), | 2665 | reverse_deps = _get_all_dependents(package_id, all_current_packages) |
2612 | pk=F('package__pk'), | ||
2613 | size=F('package__size'), | ||
2614 | ).values("name", "pk", "size").exclude( | ||
2615 | ~Q(pk__in=all_current_packages) | ||
2616 | ) | ||
2617 | |||
2618 | total_size_deps = 0 | 2666 | total_size_deps = 0 |
2619 | total_size_reverse_deps = 0 | 2667 | total_size_reverse_deps = 0 |
2620 | 2668 | ||
@@ -2658,6 +2706,11 @@ if True: | |||
2658 | 2706 | ||
2659 | else: | 2707 | else: |
2660 | recipe.appends_set.add(package) | 2708 | recipe.appends_set.add(package) |
2709 | # Make sure that package is not in the excludes set | ||
2710 | try: | ||
2711 | recipe.excludes_set.remove(package) | ||
2712 | except: | ||
2713 | pass | ||
2661 | # Add the dependencies we think will be added to the recipe | 2714 | # Add the dependencies we think will be added to the recipe |
2662 | # as a result of appending this package. | 2715 | # as a result of appending this package. |
2663 | # TODO this should recurse down the entire deps tree | 2716 | # TODO this should recurse down the entire deps tree |
@@ -2668,11 +2721,12 @@ if True: | |||
2668 | 2721 | ||
2669 | recipe.includes_set.add(cust_package) | 2722 | recipe.includes_set.add(cust_package) |
2670 | try: | 2723 | try: |
2671 | # when adding the pre-requisite package make sure it's not in the | 2724 | # When adding the pre-requisite package, make |
2672 | # excluded list from a prior removal. | 2725 | # sure it's not in the excluded list from a |
2726 | # prior removal. | ||
2673 | recipe.excludes_set.remove(cust_package) | 2727 | recipe.excludes_set.remove(cust_package) |
2674 | except Package.DoesNotExist: | 2728 | except Package.DoesNotExist: |
2675 | # Don't care if the package had never been excluded | 2729 | # Don't care if the package had never been excluded |
2676 | pass | 2730 | pass |
2677 | except: | 2731 | except: |
2678 | logger.warning("Could not add package's suggested" | 2732 | logger.warning("Could not add package's suggested" |
@@ -2688,6 +2742,19 @@ if True: | |||
2688 | recipe.excludes_set.add(package) | 2742 | recipe.excludes_set.add(package) |
2689 | else: | 2743 | else: |
2690 | recipe.appends_set.remove(package) | 2744 | recipe.appends_set.remove(package) |
2745 | all_current_packages = recipe.get_all_packages() | ||
2746 | reverse_deps_dictlist = _get_all_dependents(package.pk, all_current_packages) | ||
2747 | ids = [entry['pk'] for entry in reverse_deps_dictlist] | ||
2748 | reverse_deps = CustomImagePackage.objects.filter(id__in=ids) | ||
2749 | for r in reverse_deps: | ||
2750 | try: | ||
2751 | if r.id in included_packages: | ||
2752 | recipe.excludes_set.add(r) | ||
2753 | else: | ||
2754 | recipe.appends_set.remove(r) | ||
2755 | except: | ||
2756 | pass | ||
2757 | |||
2691 | return {"error": "ok"} | 2758 | return {"error": "ok"} |
2692 | except CustomImageRecipe.DoesNotExist: | 2759 | except CustomImageRecipe.DoesNotExist: |
2693 | return {"error": "Tried to remove package that wasn't present"} | 2760 | return {"error": "Tried to remove package that wasn't present"} |