summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2013-06-18 16:24:48 +0300
committerTimo Teräs <timo.teras@iki.fi>2013-06-19 08:33:51 +0300
commitd315c9019cf6e43dd7ecfe17e8d3896469396997 (patch)
tree68a54cb549792813700c18f19177bd1c2c52fe56
parentf91b01fea8a0e2b32ccf9d3eea8468d5312633c4 (diff)
downloadapk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.gz
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.bz2
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.xz
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.zip
upgrade: new option: --latest (-l)
Select latest version of package (if it is not pinned), and print error if it cannot be installed due to other dependencies. Together with --available, it selects the latest package which is present at least in some repository. This also fixes few solver issues with ordering of package selection that got quite apparent with this flag. Namely, we cannot "lock" a package until it's reverse dependencies are locked or not all of the solver flags are propagated properly.
-rw-r--r--src/apk_solver.h1
-rw-r--r--src/apk_solver_data.h1
-rw-r--r--src/commit.c17
-rw-r--r--src/solver.c143
-rw-r--r--src/upgrade.c6
-rw-r--r--test/basic12.test15
-rw-r--r--test/basic13.test10
-rw-r--r--test/error5.test6
8 files changed, 134 insertions, 65 deletions
diff --git a/src/apk_solver.h b/src/apk_solver.h
index 15620e9..b6067e2 100644
--- a/src/apk_solver.h
+++ b/src/apk_solver.h
@@ -33,6 +33,7 @@ struct apk_changeset {
#define APK_SOLVERF_UPGRADE 0x0001
#define APK_SOLVERF_AVAILABLE 0x0002
#define APK_SOLVERF_REINSTALL 0x0004
+#define APK_SOLVERF_LATEST 0x0008
void apk_solver_set_name_flags(struct apk_name *name,
unsigned short solver_flags,
diff --git a/src/apk_solver_data.h b/src/apk_solver_data.h
index cc41f6d..7a5e275 100644
--- a/src/apk_solver_data.h
+++ b/src/apk_solver_data.h
@@ -32,6 +32,7 @@ struct apk_solver_name_state {
unsigned locked : 1;
unsigned has_iif : 1;
unsigned has_options : 1;
+ unsigned reverse_deps_done : 1;
};
struct apk_solver_package_state {
diff --git a/src/commit.c b/src/commit.c
index 7136627..6a2580d 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -370,13 +370,18 @@ static void print_pinning_errors(struct print_state *ps, struct apk_package *pkg
if (pkg->ipkg != NULL)
return;
- if (pkg->repos & apk_db_get_pinning_mask_repos(db, APK_DEFAULT_PINNING_MASK | BIT(tag)))
- return;
- for (i = 0; i < db->num_repo_tags; i++) {
- if (pkg->repos & db->repo_tags[i].allowed_repos) {
- label_start(ps, "masked in:");
- apk_print_indented(&ps->i, db->repo_tags[i].tag);
+ if (!(pkg->repos & db->available_repos)) {
+ label_start(ps, "masked in:");
+ apk_print_indented_fmt(&ps->i, "--no-network");
+ } else {
+ if (pkg->repos & apk_db_get_pinning_mask_repos(db, APK_DEFAULT_PINNING_MASK | BIT(tag)))
+ return;
+ for (i = 0; i < db->num_repo_tags; i++) {
+ if (pkg->repos & db->repo_tags[i].allowed_repos) {
+ label_start(ps, "masked in:");
+ apk_print_indented(&ps->i, db->repo_tags[i].tag);
+ }
}
}
label_end(ps);
diff --git a/src/solver.c b/src/solver.c
index b1a078c..914baf1 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -222,11 +222,12 @@ static void discover_name(struct apk_solver_state *ss, struct apk_name *name)
}
name->ss.max_dep_chain = max(name->ss.max_dep_chain, pkg->ss.max_dep_chain);
- dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d\n",
+ dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d available=%d\n",
PKG_VER_PRINTF(pkg),
pkg->ss.tag_ok,
pkg->ss.tag_preferred,
- pkg->ss.max_dep_chain);
+ pkg->ss.max_dep_chain,
+ pkg->ss.available);
}
foreach_array_item(pname0, name->rinstall_if)
discover_name(ss, *pname0);
@@ -266,7 +267,8 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
BLOB_PRINTF(*dep->version));
name->ss.requirers += !dep->conflict;
- name_requirers_changed(ss, name);
+ if (name->ss.requirers == 1 && !dep->conflict)
+ name_requirers_changed(ss, name);
foreach_array_item(p0, name->providers) {
struct apk_package *pkg0 = p0->pkg;
@@ -294,7 +296,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
{
- struct apk_name *name0;
+ struct apk_name *name0, **pname0;
struct apk_dependency *dep;
struct apk_package *first_candidate = NULL;
struct apk_provider *p;
@@ -366,26 +368,41 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
foreach_array_item(p, name->providers)
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
- /* TODO: could merge versioning bits too */
/* propagate down common dependencies */
- foreach_array_item(dep, first_candidate->depends) {
- if (dep->conflict)
- continue;
- name0 = dep->name;
- if (name0->ss.merge_index == num_options) {
- /* common dependency name with all */
- if (name0->ss.requirers == 0) {
- dbg_printf("%s common dependency: %s\n",
- name->name, name0->name);
- name0->ss.requirers++;
- name_requirers_changed(ss, name0);
+ if (num_options == 1) {
+ /* FIXME: keeps increasing counts, use bit fields instead? */
+ foreach_array_item(dep, first_candidate->depends)
+ apply_constraint(ss, first_candidate, dep);
+ } else {
+ /* FIXME: could merge versioning bits too */
+ foreach_array_item(dep, first_candidate->depends) {
+ if (dep->conflict)
+ continue;
+ name0 = dep->name;
+ if (name0->ss.merge_index == num_options) {
+ /* common dependency name with all */
+ if (name0->ss.requirers == 0) {
+ dbg_printf("%s common dependency: %s\n",
+ name->name, name0->name);
+ name0->ss.requirers++;
+ name_requirers_changed(ss, name0);
+ }
}
+ name0->ss.merge_index = 0;
}
- name0->ss.merge_index = 0;
}
}
- dbg_printf("reconsider_name: %s [finished], has_options=%d\n",
- name->name, name->ss.has_options);
+ name->ss.reverse_deps_done = 1;
+ foreach_array_item(pname0, name->rdepends) {
+ name0 = *pname0;
+ if (name0->ss.seen && !name0->ss.locked) {
+ name->ss.reverse_deps_done = 0;
+ break;
+ }
+ }
+
+ dbg_printf("reconsider_name: %s [finished], has_options=%d, reverse_deps_done=%d\n",
+ name->name, name->ss.has_options, name->ss.reverse_deps_done);
}
static int compare_providers(struct apk_solver_state *ss,
@@ -400,50 +417,66 @@ static int compare_providers(struct apk_solver_state *ss,
if (pkgA == NULL || pkgB == NULL)
return (pkgA != NULL) - (pkgB != NULL);
- /* Prefer without errors */
- r = (int)pkgA->ss.available - (int)pkgB->ss.available;
- if (r)
- return r;
+ /* Latest version required? */
+ solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
+ if ((solver_flags & APK_SOLVERF_LATEST) &&
+ (pkgA->ss.pinning_allowed == APK_DEFAULT_PINNING_MASK) &&
+ (pkgB->ss.pinning_allowed == APK_DEFAULT_PINNING_MASK)) {
+ /* Prefer allowed pinning */
+ r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
+ if (r)
+ return r;
- /* Prefer those that were in last dependency merging group */
- r = (int)pkgA->ss.dependencies_used - (int)pkgB->ss.dependencies_used;
- if (r)
- return r;
- r = pkgB->ss.conflicts - pkgA->ss.conflicts;
- if (r)
- return r;
+ /* Prefer available */
+ if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
+ r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
+ if (r)
+ return r;
+ }
+ } else {
+ /* Prefer without errors */
+ r = (int)pkgA->ss.available - (int)pkgB->ss.available;
+ if (r)
+ return r;
- /* Prefer installed on self-upgrade */
- solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
- if (db->performing_self_update && !(solver_flags & APK_SOLVERF_UPGRADE)) {
- r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ /* Prefer those that were in last dependency merging group */
+ r = (int)pkgA->ss.dependencies_used - (int)pkgB->ss.dependencies_used;
+ if (r)
+ return r;
+ r = pkgB->ss.conflicts - pkgA->ss.conflicts;
if (r)
return r;
- }
- /* Prefer allowed pinning */
- r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
- if (r)
- return r;
+ /* Prefer installed on self-upgrade */
+ if (db->performing_self_update && !(solver_flags & APK_SOLVERF_UPGRADE)) {
+ r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ if (r)
+ return r;
+ }
- /* Prefer available */
- if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
- r = !!(pkgA->repos & db->available_repos) -
- !!(pkgB->repos & db->available_repos);
+ /* Prefer allowed pinning */
+ r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
if (r)
return r;
- }
- /* Prefer preferred pinning */
- r = (int)pkgA->ss.tag_preferred - (int)pkgB->ss.tag_preferred;
- if (r)
- return r;
+ /* Prefer available */
+ if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
+ r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
+ if (r)
+ return r;
+ }
- /* Prefer installed */
- if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
- r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ /* Prefer preferred pinning */
+ r = (int)pkgA->ss.tag_preferred - (int)pkgB->ss.tag_preferred;
if (r)
return r;
+
+ /* Prefer installed */
+ if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
+ r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ if (r)
+ return r;
+ }
}
/* Select latest by requested name */
@@ -747,17 +780,15 @@ restart:
name = NULL;
list_for_each_entry(name0, &ss->unresolved_head, ss.unresolved_list) {
- if ((!name0->ss.has_options) && name0->ss.requirers > 0) {
+ if (name0->ss.reverse_deps_done && name0->ss.requirers && !name0->ss.has_options) {
name = name0;
break;
}
if (name == NULL)
goto prefer;
- if (name0->ss.requirers == 0 && name->ss.requirers > 0)
+ if ((!!name0->ss.requirers) - (!!name->ss.requirers) < 0)
continue;
- if (name0->ss.requirers > 0 && name->ss.requirers == 0)
- goto prefer;
- if (name0->ss.max_dep_chain < name->ss.max_dep_chain)
+ if (name0->ss.max_dep_chain - name->ss.max_dep_chain < 0)
continue;
prefer:
name = name0;
diff --git a/src/upgrade.c b/src/upgrade.c
index 41d3cf7..f23ea91 100644
--- a/src/upgrade.c
+++ b/src/upgrade.c
@@ -35,6 +35,9 @@ static int upgrade_parse(void *ctx, struct apk_db_options *dbopts,
case 'a':
uctx->solver_flags |= APK_SOLVERF_AVAILABLE;
break;
+ case 'l':
+ uctx->solver_flags |= APK_SOLVERF_LATEST;
+ break;
default:
return -1;
}
@@ -131,6 +134,9 @@ static struct apk_option upgrade_options[] = {
"replacing or downgrading packages (instead of holding them) "
"if the currently installed package is no longer available "
"from any repository" },
+ { 'l', "latest",
+ "Select latest version of package (if it is not pinned), and "
+ "print error if it cannot be installed due to other dependencies" },
{ 0x10000, "no-self-upgrade",
"Do not do early upgrade of 'apk-tools' package" },
};
diff --git a/test/basic12.test b/test/basic12.test
new file mode 100644
index 0000000..f43b8ce
--- /dev/null
+++ b/test/basic12.test
@@ -0,0 +1,15 @@
+@ARGS
+--no-network
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+--latest
+upgrade
+@EXPECT
+ERROR: unsatisfiable constraints:
+ b-2:
+ masked in: --no-network
+ satisfies: a-2[b]
+ a-2:
+ masked in: --no-network
+ satisfies: world[a]
diff --git a/test/basic13.test b/test/basic13.test
new file mode 100644
index 0000000..40f5bb6
--- /dev/null
+++ b/test/basic13.test
@@ -0,0 +1,10 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a<2
+--latest
+upgrade
+@EXPECT
+ERROR: unsatisfiable constraints:
+ a-2:
+ breaks: world[a<2]
diff --git a/test/error5.test b/test/error5.test
index 949fbe8..4becb3d 100644
--- a/test/error5.test
+++ b/test/error5.test
@@ -3,6 +3,6 @@
add a>2
@EXPECT
ERROR: unsatisfiable constraints:
- d-1.5:
- breaks: a-3[d>1.5]
- satisfies: b-1[d<2.0] c-1[d>1.0]
+ d-2.0:
+ breaks: b-1[d<2.0]
+ satisfies: a-3[d>1.5] c-1[d>1.0]