summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-08-04 13:57:54 +0300
committerTimo Teras <timo.teras@iki.fi>2009-08-04 13:57:54 +0300
commitec2ade154289ce587eab3375445a33cad992c234 (patch)
tree11d7c8731afa608719330ce3d63f719b250d4171
parent8c19869c2910332913b5a4f341dbe612c691782e (diff)
downloadapk-tools-ec2ade154289ce587eab3375445a33cad992c234.tar.gz
apk-tools-ec2ade154289ce587eab3375445a33cad992c234.tar.bz2
apk-tools-ec2ade154289ce587eab3375445a33cad992c234.tar.xz
apk-tools-ec2ade154289ce587eab3375445a33cad992c234.zip
state: fix world dependencies to be honored always
previously they might have been skipped on certain situations. this also fixes some other reverse dependency enforcements and implements new "pending" state for locked name.
-rw-r--r--src/add.c3
-rw-r--r--src/cache.c8
-rw-r--r--src/del.c6
-rw-r--r--src/fetch.c3
-rw-r--r--src/state.c133
-rw-r--r--src/upgrade.c3
6 files changed, 117 insertions, 39 deletions
diff --git a/src/add.c b/src/add.c
index e89a4cd..5cff9e1 100644
--- a/src/add.c
+++ b/src/add.c
@@ -130,6 +130,9 @@ static int add_main(void *ctx, int argc, char **argv)
}
state = apk_state_new(&db);
+ if (state == NULL)
+ goto err;
+
for (i = 0; (pkgs != NULL) && i < pkgs->num; i++) {
r = apk_state_lock_dependency(state, &pkgs->item[i]);
if (r != 0) {
diff --git a/src/cache.c b/src/cache.c
index c961fc9..641cecd 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -29,12 +29,15 @@ static int cache_download(struct apk_database *db)
struct apk_change *change;
struct apk_package *pkg;
char item[PATH_MAX], cacheitem[PATH_MAX];
- int i, r;
+ int i, r = 0;
if (db->world == NULL)
return 0;
state = apk_state_new(db);
+ if (state == NULL)
+ goto err;
+
for (i = 0; i < db->world->num; i++) {
r = apk_state_lock_dependency(state, &db->world->item[i]);
if (r != 0) {
@@ -65,7 +68,8 @@ static int cache_download(struct apk_database *db)
}
err:
- apk_state_unref(state);
+ if (state != NULL)
+ apk_state_unref(state);
return r;
}
diff --git a/src/del.c b/src/del.c
index 7d4a443..df452b1 100644
--- a/src/del.c
+++ b/src/del.c
@@ -46,6 +46,9 @@ static int del_main(void *ctx, int argc, char **argv)
}
state = apk_state_new(&db);
+ if (state == NULL)
+ goto err;
+
for (i = 0; i < argc; i++) {
struct apk_dependency dep;
@@ -63,7 +66,8 @@ static int del_main(void *ctx, int argc, char **argv)
}
r = apk_state_commit(state, &db);
err:
- apk_state_unref(state);
+ if (state != NULL)
+ apk_state_unref(state);
out:
apk_db_close(&db);
diff --git a/src/fetch.c b/src/fetch.c
index f93e465..6cd2893 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -193,6 +193,9 @@ static int fetch_main(void *ctx, int argc, char **argv)
struct apk_change *change;
state = apk_state_new(&db);
+ if (state == NULL)
+ goto err;
+
r = apk_state_lock_dependency(state, &dep);
if (r != 0) {
apk_state_unref(state);
diff --git a/src/state.c b/src/state.c
index 82e3f17..28a411f 100644
--- a/src/state.c
+++ b/src/state.c
@@ -29,9 +29,22 @@ struct apk_deferred_state {
};
#endif
+int apk_state_prune_dependency(struct apk_state *state,
+ struct apk_dependency *dep);
+
+#define APK_NS_LOCKED 0x00000001
+#define APK_NS_PENDING 0x00000002
+
static int inline ns_locked(apk_name_state_t name)
{
- if (((intptr_t) name) & 0x1)
+ if (((intptr_t) name) & APK_NS_LOCKED)
+ return TRUE;
+ return FALSE;
+}
+
+static int inline ns_pending(apk_name_state_t name)
+{
+ if (((intptr_t) name) & APK_NS_PENDING)
return TRUE;
return FALSE;
}
@@ -43,12 +56,18 @@ static int ns_empty(apk_name_state_t name)
static apk_name_state_t ns_from_pkg(struct apk_package *pkg)
{
- return (apk_name_state_t) (((intptr_t) pkg) | 0x1);
+ return (apk_name_state_t) (((intptr_t) pkg) | APK_NS_LOCKED | APK_NS_PENDING);
+}
+
+static apk_name_state_t ns_from_pkg_non_pending(struct apk_package *pkg)
+{
+ return (apk_name_state_t) (((intptr_t) pkg) | APK_NS_LOCKED);
}
static struct apk_package *ns_to_pkg(apk_name_state_t name)
{
- return (struct apk_package *) (((intptr_t) name) & ~0x1);
+ return (struct apk_package *)
+ (((intptr_t) name) & ~(APK_NS_LOCKED | APK_NS_PENDING));
}
static apk_name_state_t ns_from_choices(struct apk_name_choices *nc)
@@ -117,7 +136,7 @@ static void ns_free(apk_name_state_t name)
struct apk_state *apk_state_new(struct apk_database *db)
{
struct apk_state *state;
- int num_bytes;
+ int num_bytes, i, r;
num_bytes = sizeof(struct apk_state) + db->name_id * sizeof(char *);
state = (struct apk_state*) calloc(1, num_bytes);
@@ -125,7 +144,22 @@ struct apk_state *apk_state_new(struct apk_database *db)
state->num_names = db->name_id;
list_init(&state->change_list_head);
+ /* Instantiate each 'name' target in world, and lockout incompatible
+ * choices */
+ for (i = 0; i < db->world->num; i++) {
+ r = apk_state_prune_dependency(state, &db->world->item[i]);
+ if (r < 0) {
+ apk_error("Top level dependencies for %s are "
+ "conflicting or unsatisfiable.",
+ db->world->item[i].name->name);
+ goto err;
+ }
+ }
+
return state;
+err:
+ free(state);
+ return NULL;
}
struct apk_state *apk_state_dup(struct apk_state *state)
@@ -159,20 +193,26 @@ static int apk_state_add_change(struct apk_state *state,
return 0;
}
-int apk_state_lock_dependency(struct apk_state *state,
- struct apk_dependency *dep)
+/* returns:
+ * -1 error
+ * 0 locked entry matches and is ok
+ * +n this many candidates on apk_name_choices for the name
+ */
+int apk_state_prune_dependency(struct apk_state *state,
+ struct apk_dependency *dep)
{
struct apk_name *name = dep->name;
struct apk_name_choices *c;
- struct apk_package *installed = NULL, *latest = NULL, *use;
int i;
if (name->id >= state->num_names)
return -1;
if (ns_empty(state->name[name->id])) {
- if (dep->result_mask == APK_DEPMASK_CONFLICT)
- return apk_state_lock_name(state, name, NULL);
+ if (dep->result_mask == APK_DEPMASK_CONFLICT) {
+ state->name[name->id] = ns_from_pkg(NULL);
+ return 1;
+ }
/* This name has not been visited yet.
* Construct list of candidates. */
@@ -186,16 +226,17 @@ int apk_state_lock_dependency(struct apk_state *state,
/* Locked to not-installed / remove? */
if (pkg == NULL) {
- if (dep->result_mask == APK_DEPMASK_CONFLICT)
- return 0;
- return -1;
+ if (dep->result_mask != APK_DEPMASK_CONFLICT)
+ return -1;
+ } else {
+ if (!(apk_version_compare(pkg->version, dep->version)
+ & dep->result_mask))
+ return -1;
}
- if (apk_version_compare(pkg->version, dep->version)
- & dep->result_mask)
- return 0;
-
- return -1;
+ if (ns_pending(state->name[name->id]))
+ return 1;
+ return 0;
}
/* Multiple candidates: prune incompatible versions. */
@@ -219,11 +260,30 @@ int apk_state_lock_dependency(struct apk_state *state,
if (c->num == 1) {
struct apk_package *pkg = c->pkgs[0];
name_choices_unref(c);
- state->name[name->id] = NULL;
- return apk_state_lock_name(state, name, pkg);
+ state->name[name->id] = ns_from_pkg(pkg);
+ return 1;
}
+
state->name[name->id] = ns_from_choices(c);
+ return c->num;
+}
+int apk_state_lock_dependency(struct apk_state *state,
+ struct apk_dependency *dep)
+{
+ struct apk_name *name = dep->name;
+ struct apk_name_choices *c;
+ struct apk_package *installed = NULL, *latest = NULL, *use;
+ int i, r;
+
+ r = apk_state_prune_dependency(state, dep);
+ if (r <= 0)
+ return r;
+
+ if (ns_pending(state->name[name->id]))
+ return apk_state_lock_name(state, name, ns_to_pkg(state->name[name->id]));
+
+ c = ns_to_choices(state->name[name->id]);
#if 1
/* Get latest and installed packages */
for (i = 0; i < c->num; i++) {
@@ -342,10 +402,10 @@ static int for_each_broken_reverse_depency(struct apk_state *state,
pkg0 = ns_to_pkg(state->name[name0->id]);
if (pkg0 == NULL)
continue;
- return call_if_dependency_broke(state, pkg0, name, cb);
- }
-
- if (!ns_empty(state->name[name0->id])) {
+ r = call_if_dependency_broke(state, pkg0, name, cb);
+ if (r != 0)
+ return r;
+ } else if (!ns_empty(state->name[name0->id])) {
struct apk_name_choices *ns =
ns_to_choices(state->name[name0->id]);
@@ -358,21 +418,22 @@ static int for_each_broken_reverse_depency(struct apk_state *state,
name, cb);
if (r != 0)
return r;
+ break;
}
- return 0;
- }
-
- for (j = 0; j < name0->pkgs->num; j++) {
- pkg0 = name0->pkgs->item[j];
+ } else {
+ for (j = 0; j < name0->pkgs->num; j++) {
+ pkg0 = name0->pkgs->item[j];
- if (apk_pkg_get_state(pkg0) != APK_PKG_INSTALLED)
- continue;
+ if (apk_pkg_get_state(pkg0) != APK_PKG_INSTALLED)
+ continue;
- r = call_if_dependency_broke(state,
- name0->pkgs->item[j],
- name, cb);
- if (r != 0)
- return r;
+ r = call_if_dependency_broke(state,
+ name0->pkgs->item[j],
+ name, cb);
+ if (r != 0)
+ return r;
+ break;
+ }
}
}
@@ -407,7 +468,7 @@ int apk_state_lock_name(struct apk_state *state,
return -1;
ns_free(state->name[name->id]);
- state->name[name->id] = ns_from_pkg(newpkg);
+ state->name[name->id] = ns_from_pkg_non_pending(newpkg);
if (name->pkgs != NULL) {
for (i = 0; i < name->pkgs->num; i++) {
diff --git a/src/upgrade.c b/src/upgrade.c
index ff30c81..333035f 100644
--- a/src/upgrade.c
+++ b/src/upgrade.c
@@ -41,6 +41,9 @@ static int upgrade_main(void *ctx, int argc, char **argv)
return r;
state = apk_state_new(&db);
+ if (state == NULL)
+ goto err;
+
for (i = 0; i < db.world->num; i++) {
r = apk_state_lock_dependency(state, &db.world->item[i]);
if (r != 0) {