summaryrefslogtreecommitdiff
path: root/src/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.c')
-rw-r--r--src/state.c133
1 files changed, 97 insertions, 36 deletions
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++) {