aboutsummaryrefslogtreecommitdiffstats
path: root/main/apk-tools/0001-solver-don-t-clobber-package-swaps-in-cases-where-an.patch
blob: b28bb381c70a74cee429ba3ceacc76e2b2e63e5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
From ba7b50c0f8ac7c8a88b03856037d9ca6618cccd5 Mon Sep 17 00:00:00 2001
From: William Pitcock <nenolod@dereferenced.org>
Date: Thu, 27 Apr 2017 23:23:47 +0000
Subject: [PATCH] solver: don't clobber package swaps in cases where an
 installed package is being replaced by a provider

---
 src/solver.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/solver.c b/src/solver.c
index 248fa27..5c08887 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -727,7 +727,12 @@ static void cset_track_deps_removed(struct apk_solver_state *ss, struct apk_pack
 
 static void cset_check_removal_by_deps(struct apk_solver_state *ss, struct apk_package *pkg)
 {
-	if (pkg->name->ss.requirers == 0)
+	/* NOTE: an orphaned package name may have 0 requirers because it is now being satisfied
+	 * through an alternate provider.  In these cases, we will handle this later as an adjustment
+	 * operation using cset_gen_name_change().  As such, only insert a removal into the transaction
+	 * if there is no other resolved provider.
+	 */
+	if (pkg->name->ss.requirers == 0 && pkg->name->ss.chosen.pkg == NULL)
 		cset_gen_name_remove(ss, pkg);
 }
 
@@ -775,12 +780,16 @@ static void cset_gen_name_change(struct apk_solver_state *ss, struct apk_name *n
 	if (name->ss.in_changeset) return;
 
 	pkg = name->ss.chosen.pkg;
-	if (pkg == NULL) {
-		/* Package removal */
+	if (pkg == NULL || pkg->name != name) {
+		/* Original package dependency name was orphaned, emit a removal.
+		 * See cset_gen_name_remove() for more details. */
 		opkg = name->ss.installed_pkg;
 		if (opkg) cset_gen_name_remove(ss, opkg);
 		name->ss.in_changeset = 1;
-		return;
+
+		/* If a replacement is not provided, then we're done here. */
+		if (pkg == NULL)
+			return;
 	}
 	if (pkg->ss.in_changeset) return;
 
@@ -881,8 +890,12 @@ static void generate_changeset(struct apk_solver_state *ss, struct apk_dependenc
 	foreach_array_item(d, world)
 		cset_gen_dep(ss, NULL, d);
 
+	/* NOTE: We used to call cset_gen_name_remove() directly here.  While slightly faster, this clobbered
+	 * dependency nodes where a new package was provided under a different name (using provides).  As such,
+	 * treat everything as a change first and then call cset_gen_name_remove() from there if appropriate.
+	 */
 	list_for_each_entry(ipkg, &ss->db->installed.packages, installed_pkgs_list)
-		cset_gen_name_remove(ss, ipkg->pkg);
+		cset_gen_name_change(ss, ipkg->pkg->name);
 
 	changeset->num_total_changes =
 		changeset->num_install +
-- 
2.12.2