applets: start using solver code
still todo: - 'fix' is missing - 'del -R' does not work - 'upgrade' does not do self-upgrade first ... and a lot of testing.cute-signatures
parent
0e24207c2e
commit
a5a7021658
|
@ -1,6 +1,7 @@
|
||||||
src/apk
|
src/apk
|
||||||
src/apk_test
|
src/apk_test
|
||||||
src/apk.static
|
src/apk.static
|
||||||
|
test/*.got
|
||||||
*.o
|
*.o
|
||||||
*.d
|
*.d
|
||||||
*.cmd
|
*.cmd
|
||||||
|
|
|
@ -19,11 +19,11 @@ $(error Build dependencies are not met)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
progs-y += apk
|
progs-y += apk
|
||||||
apk-objs := apk.o add.o del.o fix.o update.o info.o \
|
apk-objs := apk.o add.o del.o update.o info.o \
|
||||||
search.o upgrade.o cache.o ver.o index.o fetch.o \
|
search.o upgrade.o cache.o ver.o index.o fetch.o \
|
||||||
audit.o verify.o dot.o
|
audit.o verify.o dot.o
|
||||||
|
|
||||||
libapk.so-objs := common.o state.o database.o package.o archive.o \
|
libapk.so-objs := common.o database.o package.o archive.o \
|
||||||
version.o io.o url.o gunzip.o blob.o hash.o print.o \
|
version.o io.o url.o gunzip.o blob.o hash.o print.o \
|
||||||
solver.o
|
solver.o
|
||||||
|
|
||||||
|
|
49
src/add.c
49
src/add.c
|
@ -13,11 +13,12 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
#include "apk_solver.h"
|
||||||
|
|
||||||
struct add_ctx {
|
struct add_ctx {
|
||||||
const char *virtpkg;
|
const char *virtpkg;
|
||||||
|
unsigned short solver_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int add_parse(void *ctx, struct apk_db_options *dbopts,
|
static int add_parse(void *ctx, struct apk_db_options *dbopts,
|
||||||
|
@ -30,7 +31,7 @@ static int add_parse(void *ctx, struct apk_db_options *dbopts,
|
||||||
dbopts->open_flags |= APK_OPENF_CREATE;
|
dbopts->open_flags |= APK_OPENF_CREATE;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
apk_flags |= APK_UPGRADE;
|
actx->solver_flags |= APK_SOLVERF_UPGRADE;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
actx->virtpkg = optarg;
|
actx->virtpkg = optarg;
|
||||||
|
@ -60,11 +61,12 @@ static int non_repository_check(struct apk_database *db)
|
||||||
static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct add_ctx *actx = (struct add_ctx *) ctx;
|
struct add_ctx *actx = (struct add_ctx *) ctx;
|
||||||
struct apk_state *state = NULL;
|
|
||||||
struct apk_package *virtpkg = NULL;
|
struct apk_package *virtpkg = NULL;
|
||||||
struct apk_dependency virtdep;
|
struct apk_dependency virtdep;
|
||||||
struct apk_dependency *deps;
|
struct apk_dependency_array *world = NULL;
|
||||||
int i, r = 0, num_deps = 0, errors = 0;
|
int i, r = 0;
|
||||||
|
|
||||||
|
apk_dependency_array_copy(&world, db->world);
|
||||||
|
|
||||||
if (actx->virtpkg) {
|
if (actx->virtpkg) {
|
||||||
if (non_repository_check(db))
|
if (non_repository_check(db))
|
||||||
|
@ -82,13 +84,8 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
virtpkg->description = strdup("virtual meta package");
|
virtpkg->description = strdup("virtual meta package");
|
||||||
virtpkg->arch = apk_blob_atomize(APK_BLOB_STR("noarch"));
|
virtpkg->arch = apk_blob_atomize(APK_BLOB_STR("noarch"));
|
||||||
apk_dep_from_pkg(&virtdep, db, virtpkg);
|
apk_dep_from_pkg(&virtdep, db, virtpkg);
|
||||||
virtdep.name->flags |= APK_NAME_TOPLEVEL;
|
|
||||||
virtpkg = apk_db_pkg_add(db, virtpkg);
|
virtpkg = apk_db_pkg_add(db, virtpkg);
|
||||||
num_deps = 1;
|
}
|
||||||
} else
|
|
||||||
num_deps = argc;
|
|
||||||
|
|
||||||
deps = alloca(sizeof(struct apk_dependency) * num_deps);
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
struct apk_dependency dep;
|
struct apk_dependency dep;
|
||||||
|
@ -117,35 +114,15 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
|
|
||||||
if (virtpkg)
|
if (virtpkg)
|
||||||
apk_deps_add(&virtpkg->depends, &dep);
|
apk_deps_add(&virtpkg->depends, &dep);
|
||||||
else {
|
else
|
||||||
deps[i] = dep;
|
apk_deps_add(&world, &dep);
|
||||||
deps[i].name->flags |= APK_NAME_TOPLEVEL_OVERRIDE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (virtpkg)
|
if (virtpkg)
|
||||||
deps[0] = virtdep;
|
apk_deps_add(&world, &virtdep);
|
||||||
|
|
||||||
state = apk_state_new(db);
|
r = apk_solver_commit(db, actx->solver_flags, world);
|
||||||
if (state == NULL)
|
apk_dependency_array_free(&world);
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (i = 0; i < num_deps; i++) {
|
|
||||||
r = apk_state_lock_dependency(state, &deps[i]);
|
|
||||||
if (r == 0) {
|
|
||||||
apk_deps_add(&db->world, &deps[i]);
|
|
||||||
deps[i].name->flags |= APK_NAME_TOPLEVEL;
|
|
||||||
} else {
|
|
||||||
errors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errors && !(apk_flags & APK_FORCE)) {
|
|
||||||
apk_state_print_errors(state);
|
|
||||||
r = -1;
|
|
||||||
} else {
|
|
||||||
r = apk_state_commit(state);
|
|
||||||
}
|
|
||||||
if (state != NULL)
|
|
||||||
apk_state_unref(state);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,15 +81,12 @@ struct apk_db_dir_instance {
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define APK_NAME_TOPLEVEL 0x0001
|
|
||||||
#define APK_NAME_REINSTALL 0x0002
|
|
||||||
#define APK_NAME_TOPLEVEL_OVERRIDE 0x0004
|
|
||||||
#define APK_NAME_VISITED 0x8000
|
|
||||||
|
|
||||||
struct apk_name {
|
struct apk_name {
|
||||||
apk_hash_node hash_node;
|
apk_hash_node hash_node;
|
||||||
unsigned int id;
|
union {
|
||||||
unsigned int flags;
|
int state_int;
|
||||||
|
void *state_ptr;
|
||||||
|
};
|
||||||
char *name;
|
char *name;
|
||||||
struct apk_package_array *pkgs;
|
struct apk_package_array *pkgs;
|
||||||
struct apk_name_array *rdepends;
|
struct apk_name_array *rdepends;
|
||||||
|
@ -121,7 +118,7 @@ struct apk_db_options {
|
||||||
struct apk_database {
|
struct apk_database {
|
||||||
char *root;
|
char *root;
|
||||||
int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd;
|
int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd;
|
||||||
unsigned name_id, num_repos;
|
unsigned num_repos;
|
||||||
const char *cache_dir;
|
const char *cache_dir;
|
||||||
char *cache_remount_dir;
|
char *cache_remount_dir;
|
||||||
apk_blob_t *arch;
|
apk_blob_t *arch;
|
||||||
|
|
|
@ -56,14 +56,11 @@ extern char **apk_argv;
|
||||||
#define APK_SIMULATE 0x0002
|
#define APK_SIMULATE 0x0002
|
||||||
#define APK_CLEAN_PROTECTED 0x0004
|
#define APK_CLEAN_PROTECTED 0x0004
|
||||||
#define APK_PROGRESS 0x0008
|
#define APK_PROGRESS 0x0008
|
||||||
#define APK_UPGRADE 0x0010
|
|
||||||
#define APK_RECURSIVE 0x0020
|
#define APK_RECURSIVE 0x0020
|
||||||
#define APK_PREFER_AVAILABLE 0x0040
|
|
||||||
#define APK_UPDATE_CACHE 0x0080
|
#define APK_UPDATE_CACHE 0x0080
|
||||||
#define APK_ALLOW_UNTRUSTED 0x0100
|
#define APK_ALLOW_UNTRUSTED 0x0100
|
||||||
#define APK_PURGE 0x0200
|
#define APK_PURGE 0x0200
|
||||||
#define APK_INTERACTIVE 0x0400
|
#define APK_INTERACTIVE 0x0400
|
||||||
#define APK_RECURSIVE_DELETE 0x0800
|
|
||||||
#define APK_NO_NETWORK 0x1000
|
#define APK_NO_NETWORK 0x1000
|
||||||
#define APK_OVERLAY_FROM_STDIN 0x2000
|
#define APK_OVERLAY_FROM_STDIN 0x2000
|
||||||
|
|
||||||
|
@ -108,6 +105,12 @@ void *apk_array_resize(void *array, size_t new_size, size_t elem_size);
|
||||||
{ \
|
{ \
|
||||||
*a = apk_array_resize(*a, size, sizeof(elem_type_name));\
|
*a = apk_array_resize(*a, size, sizeof(elem_type_name));\
|
||||||
} \
|
} \
|
||||||
|
static inline void \
|
||||||
|
array_type_name##_copy(struct array_type_name **a, struct array_type_name *b)\
|
||||||
|
{ \
|
||||||
|
*a = apk_array_resize(*a, b->num, sizeof(elem_type_name));\
|
||||||
|
memcpy((*a)->item, b->item, b->num * sizeof(elem_type_name));\
|
||||||
|
} \
|
||||||
static inline elem_type_name * \
|
static inline elem_type_name * \
|
||||||
array_type_name##_add(struct array_type_name **a) \
|
array_type_name##_add(struct array_type_name **a) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -22,12 +22,19 @@ struct apk_changeset {
|
||||||
struct apk_change_array *changes;
|
struct apk_change_array *changes;
|
||||||
};
|
};
|
||||||
|
|
||||||
void apk_solver_sort(struct apk_database *db);
|
#define APK_SOLVERF_UPGRADE 0x0001
|
||||||
int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world,
|
#define APK_SOLVERF_AVAILABLE 0x0002
|
||||||
struct apk_package_array **solution, int allow_errors);
|
#define APK_SOLVERF_REINSTALL 0x0004
|
||||||
int apk_solver_generate_changeset(struct apk_database *db,
|
|
||||||
struct apk_package_array *solution,
|
int apk_solver_solve(struct apk_database *db,
|
||||||
struct apk_changeset *changeset);
|
unsigned short solver_flags,
|
||||||
|
struct apk_dependency_array *world,
|
||||||
|
struct apk_package_array **solution,
|
||||||
|
struct apk_changeset *changeset);
|
||||||
|
|
||||||
|
int apk_solver_commit(struct apk_database *db,
|
||||||
|
unsigned short solver_flags,
|
||||||
|
struct apk_dependency_array *world);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/* apk_state.h - Alpine Package Keeper (APK)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
|
|
||||||
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 as published
|
|
||||||
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef APK_STATE_H
|
|
||||||
#define APK_STATE_H
|
|
||||||
|
|
||||||
#include "apk_database.h"
|
|
||||||
|
|
||||||
typedef void *apk_name_state_t;
|
|
||||||
|
|
||||||
struct apk_change {
|
|
||||||
struct list_head change_list;
|
|
||||||
struct apk_package *oldpkg;
|
|
||||||
struct apk_package *newpkg;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct apk_state {
|
|
||||||
unsigned int refs, num_names, num_changes;
|
|
||||||
int print_ok;
|
|
||||||
struct apk_database *db;
|
|
||||||
struct list_head change_list_head;
|
|
||||||
struct apk_package_array *conflicts;
|
|
||||||
struct apk_name_array *missing;
|
|
||||||
apk_name_state_t name[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct apk_state *apk_state_new(struct apk_database *db);
|
|
||||||
struct apk_state *apk_state_dup(struct apk_state *state);
|
|
||||||
void apk_state_unref(struct apk_state *state);
|
|
||||||
|
|
||||||
void apk_state_print_errors(struct apk_state *state);
|
|
||||||
int apk_state_commit(struct apk_state *state);
|
|
||||||
int apk_state_lock_dependency(struct apk_state *state,
|
|
||||||
struct apk_dependency *dep);
|
|
||||||
int apk_state_lock_name(struct apk_state *state,
|
|
||||||
struct apk_name *name,
|
|
||||||
struct apk_package *newpkg);
|
|
||||||
|
|
||||||
#endif
|
|
25
src/cache.c
25
src/cache.c
|
@ -17,36 +17,30 @@
|
||||||
#include "apk_defines.h"
|
#include "apk_defines.h"
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
#include "apk_solver.h"
|
||||||
|
|
||||||
#define CACHE_CLEAN BIT(0)
|
#define CACHE_CLEAN BIT(0)
|
||||||
#define CACHE_DOWNLOAD BIT(1)
|
#define CACHE_DOWNLOAD BIT(1)
|
||||||
|
|
||||||
static int cache_download(struct apk_database *db)
|
static int cache_download(struct apk_database *db)
|
||||||
{
|
{
|
||||||
struct apk_state *state;
|
struct apk_changeset changeset;
|
||||||
struct apk_change *change;
|
struct apk_change *change;
|
||||||
struct apk_package *pkg;
|
struct apk_package *pkg;
|
||||||
struct apk_repository *repo;
|
struct apk_repository *repo;
|
||||||
char item[PATH_MAX], cacheitem[PATH_MAX];
|
char item[PATH_MAX], cacheitem[PATH_MAX];
|
||||||
int i, r = 0;
|
int i, r = 0;
|
||||||
|
|
||||||
state = apk_state_new(db);
|
r = apk_solver_solve(db, 0, db->world, NULL, &changeset);
|
||||||
if (state == NULL)
|
if (r != 0) {
|
||||||
goto err;
|
apk_error("Unable to select packages. Run apk fix.");
|
||||||
|
return r;
|
||||||
for (i = 0; i < db->world->num; i++) {
|
|
||||||
r = apk_state_lock_dependency(state, &db->world->item[i]);
|
|
||||||
if (r != 0) {
|
|
||||||
apk_error("Unable to select version for '%s': %d",
|
|
||||||
db->world->item[i].name->name, r);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(change, &state->change_list_head, change_list) {
|
for (i = 0; i < changeset.changes->num; i++) {
|
||||||
|
change = &changeset.changes->item[i];
|
||||||
pkg = change->newpkg;
|
pkg = change->newpkg;
|
||||||
|
|
||||||
apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
|
apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
|
||||||
|
@ -63,9 +57,6 @@ static int cache_download(struct apk_database *db)
|
||||||
APK_SIGN_VERIFY_IDENTITY);
|
APK_SIGN_VERIFY_IDENTITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
|
||||||
if (state != NULL)
|
|
||||||
apk_state_unref(state);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "apk_defines.h"
|
#include "apk_defines.h"
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_archive.h"
|
#include "apk_archive.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
@ -207,7 +206,6 @@ struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pn->name = apk_blob_cstr(name);
|
pn->name = apk_blob_cstr(name);
|
||||||
pn->id = db->name_id++;
|
|
||||||
apk_package_array_init(&pn->pkgs);
|
apk_package_array_init(&pn->pkgs);
|
||||||
apk_name_array_init(&pn->rdepends);
|
apk_name_array_init(&pn->rdepends);
|
||||||
apk_name_array_init(&pn->rinstall_if);
|
apk_name_array_init(&pn->rinstall_if);
|
||||||
|
@ -885,7 +883,7 @@ static int apk_db_read_state(struct apk_database *db, int flags)
|
||||||
struct apk_istream *is;
|
struct apk_istream *is;
|
||||||
struct apk_bstream *bs;
|
struct apk_bstream *bs;
|
||||||
apk_blob_t blob;
|
apk_blob_t blob;
|
||||||
int i, r;
|
int r;
|
||||||
|
|
||||||
/* Read:
|
/* Read:
|
||||||
* 1. installed repository
|
* 1. installed repository
|
||||||
|
@ -901,9 +899,6 @@ static int apk_db_read_state(struct apk_database *db, int flags)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
apk_deps_parse(db, &db->world, blob);
|
apk_deps_parse(db, &db->world, blob);
|
||||||
free(blob.ptr);
|
free(blob.ptr);
|
||||||
|
|
||||||
for (i = 0; i < db->world->num; i++)
|
|
||||||
db->world->item[i].name->flags |= APK_NAME_TOPLEVEL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & APK_OPENF_NO_INSTALLED)) {
|
if (!(flags & APK_OPENF_NO_INSTALLED)) {
|
||||||
|
|
38
src/del.c
38
src/del.c
|
@ -11,17 +11,16 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
#include "apk_solver.h"
|
||||||
|
|
||||||
static int del_parse(void *ctx, struct apk_db_options *db,
|
static int del_parse(void *ctx, struct apk_db_options *db,
|
||||||
int optch, int optindex, const char *optarg)
|
int optch, int optindex, const char *optarg)
|
||||||
{
|
{
|
||||||
switch (optch) {
|
switch (optch) {
|
||||||
case 'r':
|
case 'r':
|
||||||
apk_flags |= APK_RECURSIVE_DELETE;
|
/* FIXME: Reimplement recursive delete. */
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -30,40 +29,17 @@ static int del_parse(void *ctx, struct apk_db_options *db,
|
||||||
|
|
||||||
static int del_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
static int del_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct apk_state *state;
|
|
||||||
struct apk_name *name;
|
struct apk_name *name;
|
||||||
|
struct apk_dependency_array *world = NULL;
|
||||||
int i, r = 0;
|
int i, r = 0;
|
||||||
|
|
||||||
|
apk_dependency_array_copy(&world, db->world);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
name = apk_db_get_name(db, APK_BLOB_STR(argv[i]));
|
name = apk_db_get_name(db, APK_BLOB_STR(argv[i]));
|
||||||
name->flags &= ~APK_NAME_TOPLEVEL;
|
apk_deps_del(&world, name);
|
||||||
name->flags |= APK_NAME_TOPLEVEL_OVERRIDE;
|
|
||||||
apk_deps_del(&db->world, name);
|
|
||||||
}
|
}
|
||||||
|
r = apk_solver_commit(db, 0, world);
|
||||||
state = apk_state_new(db);
|
apk_dependency_array_free(&world);
|
||||||
if (state == NULL)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
|
||||||
struct apk_dependency dep;
|
|
||||||
|
|
||||||
name = apk_db_get_name(db, APK_BLOB_STR(argv[i]));
|
|
||||||
dep = (struct apk_dependency) {
|
|
||||||
.name = name,
|
|
||||||
.version = apk_blob_atomize(APK_BLOB_NULL),
|
|
||||||
.result_mask = APK_DEPMASK_CONFLICT,
|
|
||||||
};
|
|
||||||
|
|
||||||
r |= apk_state_lock_dependency(state, &dep);
|
|
||||||
}
|
|
||||||
if (r == 0)
|
|
||||||
r = apk_state_commit(state);
|
|
||||||
else
|
|
||||||
apk_state_print_errors(state);
|
|
||||||
err:
|
|
||||||
if (state != NULL)
|
|
||||||
apk_state_unref(state);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,10 +71,10 @@ static int dump_pkg(struct dot_ctx *ctx, struct apk_package *pkg)
|
||||||
printf(" \"" PKG_VER_FMT "\" -> \"%s\" [color=red];\n",
|
printf(" \"" PKG_VER_FMT "\" -> \"%s\" [color=red];\n",
|
||||||
PKG_VER_PRINTF(pkg),
|
PKG_VER_PRINTF(pkg),
|
||||||
name->name);
|
name->name);
|
||||||
if (!(name->flags & APK_NAME_VISITED)) {
|
if (!name->state_int) {
|
||||||
printf(" \"%s\" [style=dashed, color=red, fontcolor=red, shape=octagon];\n",
|
printf(" \"%s\" [style=dashed, color=red, fontcolor=red, shape=octagon];\n",
|
||||||
name->name);
|
name->name);
|
||||||
name->flags |= APK_NAME_VISITED;
|
name->state_int = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (j = 0; j < name->pkgs->num; j++) {
|
for (j = 0; j < name->pkgs->num; j++) {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_io.h"
|
#include "apk_io.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
|
||||||
|
@ -180,6 +179,7 @@ static int fetch_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
.result_mask = APK_DEPMASK_REQUIRE,
|
.result_mask = APK_DEPMASK_REQUIRE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (fctx->flags & FETCH_RECURSIVE) {
|
if (fctx->flags & FETCH_RECURSIVE) {
|
||||||
struct apk_state *state;
|
struct apk_state *state;
|
||||||
struct apk_change *change;
|
struct apk_change *change;
|
||||||
|
@ -203,7 +203,9 @@ static int fetch_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
apk_state_unref(state);
|
apk_state_unref(state);
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
struct apk_package *pkg = NULL;
|
struct apk_package *pkg = NULL;
|
||||||
|
|
||||||
for (j = 0; j < dep.name->pkgs->num; j++)
|
for (j = 0; j < dep.name->pkgs->num; j++)
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "apk_state.h"
|
#include "apk_state.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
|
||||||
|
/* FIXME: reimplement fix applet */
|
||||||
|
|
||||||
struct fix_ctx {
|
struct fix_ctx {
|
||||||
unsigned int reinstall : 1;
|
unsigned int reinstall : 1;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
|
||||||
struct info_ctx {
|
struct info_ctx {
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "apk_archive.h"
|
#include "apk_archive.h"
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
|
||||||
void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to)
|
void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to)
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
|
|
||||||
struct search_ctx {
|
struct search_ctx {
|
||||||
int (*match)(struct apk_package *pkg, const char *str);
|
int (*match)(struct apk_package *pkg, const char *str);
|
||||||
|
|
552
src/solver.c
552
src/solver.c
|
@ -15,6 +15,8 @@
|
||||||
#include "apk_package.h"
|
#include "apk_package.h"
|
||||||
#include "apk_solver.h"
|
#include "apk_solver.h"
|
||||||
|
|
||||||
|
#include "apk_print.h"
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define dbg_printf(args...) fprintf(stderr, args)
|
#define dbg_printf(args...) fprintf(stderr, args)
|
||||||
|
@ -43,6 +45,7 @@ struct apk_package_state {
|
||||||
struct apk_name_state {
|
struct apk_name_state {
|
||||||
struct list_head unsolved_list;
|
struct list_head unsolved_list;
|
||||||
struct apk_package *chosen;
|
struct apk_package *chosen;
|
||||||
|
unsigned short solver_flags;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
unsigned short requirers;
|
unsigned short requirers;
|
||||||
unsigned short install_ifs;
|
unsigned short install_ifs;
|
||||||
|
@ -50,15 +53,14 @@ struct apk_name_state {
|
||||||
|
|
||||||
struct apk_solver_state {
|
struct apk_solver_state {
|
||||||
struct apk_database *db;
|
struct apk_database *db;
|
||||||
struct apk_name_state *name_state;
|
|
||||||
unsigned num_topology_positions;
|
unsigned num_topology_positions;
|
||||||
|
|
||||||
struct list_head unsolved_list_head;
|
struct list_head unsolved_list_head;
|
||||||
struct apk_package *latest_decision;
|
struct apk_package *latest_decision;
|
||||||
unsigned int topology_position;
|
unsigned int topology_position;
|
||||||
unsigned int assigned_names;
|
unsigned int assigned_names;
|
||||||
|
unsigned short solver_flags;
|
||||||
unsigned short cur_unsatisfiable;
|
unsigned short cur_unsatisfiable;
|
||||||
unsigned short allow_errors;
|
|
||||||
|
|
||||||
struct apk_package_array *best_solution;
|
struct apk_package_array *best_solution;
|
||||||
unsigned short best_unsatisfiable;
|
unsigned short best_unsatisfiable;
|
||||||
|
@ -69,11 +71,18 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
|
||||||
static void push_decision(struct apk_solver_state *ss, struct apk_package *pkg,
|
static void push_decision(struct apk_solver_state *ss, struct apk_package *pkg,
|
||||||
int flags);
|
int flags);
|
||||||
|
|
||||||
static inline struct apk_package_state *pkg_to_ps(struct apk_package *pkg)
|
static struct apk_package_state *pkg_to_ps(struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
return (struct apk_package_state*) pkg->state_ptr;
|
return (struct apk_package_state*) pkg->state_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct apk_name_state *name_to_ns(struct apk_name *name)
|
||||||
|
{
|
||||||
|
if (name->state_ptr == NULL)
|
||||||
|
name->state_ptr = calloc(1, sizeof(struct apk_name_state));
|
||||||
|
return (struct apk_name_state*) name->state_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int pkg_available(struct apk_database *db, struct apk_package *pkg)
|
static inline int pkg_available(struct apk_database *db, struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
if (pkg->installed_size == 0)
|
if (pkg->installed_size == 0)
|
||||||
|
@ -151,6 +160,7 @@ static void sort_hard_dependencies(struct apk_solver_state *ss, struct apk_packa
|
||||||
ps = pkg_to_ps(pkg);
|
ps = pkg_to_ps(pkg);
|
||||||
if (ps->topology_hard)
|
if (ps->topology_hard)
|
||||||
return;
|
return;
|
||||||
|
ps->topology_hard = -1;
|
||||||
|
|
||||||
/* Consider hard dependencies only */
|
/* Consider hard dependencies only */
|
||||||
foreach_dependency_pkg(ss, pkg->depends, sort_hard_dependencies);
|
foreach_dependency_pkg(ss, pkg->depends, sort_hard_dependencies);
|
||||||
|
@ -170,6 +180,7 @@ static void sort_soft_dependencies(struct apk_solver_state *ss, struct apk_packa
|
||||||
ps = pkg_to_ps(pkg);
|
ps = pkg_to_ps(pkg);
|
||||||
if (ps->topology_soft != ps->topology_hard)
|
if (ps->topology_soft != ps->topology_hard)
|
||||||
return;
|
return;
|
||||||
|
ps->topology_soft = -1;
|
||||||
|
|
||||||
/* Soft reverse dependencies aka. install_if */
|
/* Soft reverse dependencies aka. install_if */
|
||||||
foreach_rinstall_if_pkg(ss, pkg, sort_hard_dependencies);
|
foreach_rinstall_if_pkg(ss, pkg, sort_hard_dependencies);
|
||||||
|
@ -200,9 +211,11 @@ static void prepare_name(struct apk_solver_state *ss, struct apk_name *name,
|
||||||
for (i = 0; i < name->pkgs->num; i++) {
|
for (i = 0; i < name->pkgs->num; i++) {
|
||||||
struct apk_package *pkg = name->pkgs->item[i];
|
struct apk_package *pkg = name->pkgs->item[i];
|
||||||
struct apk_package_state *ps = pkg_to_ps(pkg);
|
struct apk_package_state *ps = pkg_to_ps(pkg);
|
||||||
|
struct apk_name_state *ns = name_to_ns(pkg->name);
|
||||||
|
|
||||||
/* if package is needed for (re-)install */
|
/* if package is needed for (re-)install */
|
||||||
if ((name->flags & APK_NAME_REINSTALL) || (pkg->ipkg == NULL)) {
|
if ((pkg->ipkg == NULL) ||
|
||||||
|
(ns->solver_flags & APK_SOLVERF_REINSTALL)) {
|
||||||
/* and it's not available, we can't use it */
|
/* and it's not available, we can't use it */
|
||||||
if (!pkg_available(ss->db, pkg))
|
if (!pkg_available(ss->db, pkg))
|
||||||
ps->conflicts++;
|
ps->conflicts++;
|
||||||
|
@ -237,7 +250,7 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
|
||||||
ps0->conflicts != 0)
|
ps0->conflicts != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (apk_flags & APK_PREFER_AVAILABLE) {
|
if (ss->solver_flags & APK_SOLVERF_AVAILABLE) {
|
||||||
/* pkg available, pkg0 not */
|
/* pkg available, pkg0 not */
|
||||||
if (pkg->repos != 0 && pkg0->repos == 0)
|
if (pkg->repos != 0 && pkg0->repos == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -246,7 +259,7 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
|
||||||
return APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH;
|
return APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(apk_flags & APK_UPGRADE)) {
|
if (!(ss->solver_flags & APK_SOLVERF_UPGRADE)) {
|
||||||
/* not upgrading, prefer the installed package */
|
/* not upgrading, prefer the installed package */
|
||||||
if (pkg->ipkg == NULL && pkg0->ipkg != NULL)
|
if (pkg->ipkg == NULL && pkg0->ipkg != NULL)
|
||||||
return APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH;
|
return APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH;
|
||||||
|
@ -269,13 +282,13 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
|
||||||
|
|
||||||
static int install_if_missing(struct apk_solver_state *ss, struct apk_package *pkg)
|
static int install_if_missing(struct apk_solver_state *ss, struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
struct apk_name_state *ns = &ss->name_state[pkg->name->id];
|
struct apk_name_state *ns;
|
||||||
int i, missing = 0;
|
int i, missing = 0;
|
||||||
|
|
||||||
for (i = 0; i < pkg->install_if->num; i++) {
|
for (i = 0; i < pkg->install_if->num; i++) {
|
||||||
struct apk_dependency *dep = &pkg->install_if->item[i];
|
struct apk_dependency *dep = &pkg->install_if->item[i];
|
||||||
|
|
||||||
ns = &ss->name_state[dep->name->id];
|
ns = name_to_ns(dep->name);
|
||||||
if (!(ns->flags & APK_NAMESTF_LOCKED) ||
|
if (!(ns->flags & APK_NAMESTF_LOCKED) ||
|
||||||
!apk_dep_is_satisfied(dep, ns->chosen))
|
!apk_dep_is_satisfied(dep, ns->chosen))
|
||||||
missing++;
|
missing++;
|
||||||
|
@ -354,7 +367,7 @@ static void trigger_install_if(struct apk_solver_state *ss,
|
||||||
struct apk_package *pkg)
|
struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
if (install_if_missing(ss, pkg) == 0) {
|
if (install_if_missing(ss, pkg) == 0) {
|
||||||
struct apk_name_state *ns = ns = &ss->name_state[pkg->name->id];
|
struct apk_name_state *ns = ns = name_to_ns(pkg->name);
|
||||||
|
|
||||||
dbg_printf("trigger_install_if: " PKG_VER_FMT " triggered\n",
|
dbg_printf("trigger_install_if: " PKG_VER_FMT " triggered\n",
|
||||||
PKG_VER_PRINTF(pkg));
|
PKG_VER_PRINTF(pkg));
|
||||||
|
@ -367,7 +380,7 @@ static void untrigger_install_if(struct apk_solver_state *ss,
|
||||||
struct apk_package *pkg)
|
struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
if (install_if_missing(ss, pkg) != 1) {
|
if (install_if_missing(ss, pkg) != 1) {
|
||||||
struct apk_name_state *ns = ns = &ss->name_state[pkg->name->id];
|
struct apk_name_state *ns = name_to_ns(pkg->name);
|
||||||
|
|
||||||
dbg_printf("untrigger_install_if: " PKG_VER_FMT " no longer triggered\n",
|
dbg_printf("untrigger_install_if: " PKG_VER_FMT " no longer triggered\n",
|
||||||
PKG_VER_PRINTF(pkg));
|
PKG_VER_PRINTF(pkg));
|
||||||
|
@ -380,7 +393,7 @@ static void apply_decision(struct apk_solver_state *ss,
|
||||||
struct apk_package *pkg,
|
struct apk_package *pkg,
|
||||||
struct apk_package_state *ps)
|
struct apk_package_state *ps)
|
||||||
{
|
{
|
||||||
struct apk_name_state *ns = &ss->name_state[pkg->name->id];
|
struct apk_name_state *ns = name_to_ns(pkg->name);
|
||||||
|
|
||||||
dbg_printf("apply_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
dbg_printf("apply_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
||||||
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
||||||
|
@ -407,7 +420,7 @@ static void undo_decision(struct apk_solver_state *ss,
|
||||||
struct apk_package *pkg,
|
struct apk_package *pkg,
|
||||||
struct apk_package_state *ps)
|
struct apk_package_state *ps)
|
||||||
{
|
{
|
||||||
struct apk_name_state *ns = &ss->name_state[pkg->name->id];
|
struct apk_name_state *ns = name_to_ns(pkg->name);
|
||||||
|
|
||||||
dbg_printf("undo_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
dbg_printf("undo_decision: " PKG_VER_FMT " %s\n", PKG_VER_PRINTF(pkg),
|
||||||
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
(ps->flags & APK_PKGSTF_INSTALL) ? "INSTALL" : "NO_INSTALL");
|
||||||
|
@ -497,7 +510,7 @@ static int next_branch(struct apk_solver_state *ss)
|
||||||
static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
|
static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
|
||||||
{
|
{
|
||||||
struct apk_name *name = dep->name;
|
struct apk_name *name = dep->name;
|
||||||
struct apk_name_state *ns = &ss->name_state[name->id];
|
struct apk_name_state *ns = name_to_ns(name);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
prepare_name(ss, name, ns);
|
prepare_name(ss, name, ns);
|
||||||
|
@ -533,7 +546,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
|
||||||
static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
|
static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
|
||||||
{
|
{
|
||||||
struct apk_name *name = dep->name;
|
struct apk_name *name = dep->name;
|
||||||
struct apk_name_state *ns = &ss->name_state[name->id];
|
struct apk_name_state *ns = name_to_ns(name);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ns->flags & APK_NAMESTF_LOCKED) {
|
if (ns->flags & APK_NAMESTF_LOCKED) {
|
||||||
|
@ -589,7 +602,7 @@ static int expand_branch(struct apk_solver_state *ss)
|
||||||
|
|
||||||
/* someone needs to provide this name -- find next eligible
|
/* someone needs to provide this name -- find next eligible
|
||||||
* provider candidate */
|
* provider candidate */
|
||||||
ns = &ss->name_state[pkg0->name->id];
|
ns = name_to_ns(pkg0->name);
|
||||||
dbg_printf("expand_branch: %s\n", pkg0->name->name);
|
dbg_printf("expand_branch: %s\n", pkg0->name->name);
|
||||||
|
|
||||||
push_decision(ss, pkg0, get_pkg_expansion_flags(ss, pkg0));
|
push_decision(ss, pkg0, get_pkg_expansion_flags(ss, pkg0));
|
||||||
|
@ -633,27 +646,123 @@ static int compare_package_name(const void *p1, const void *p2)
|
||||||
return strcmp((*c1)->name->name, (*c2)->name->name);
|
return strcmp((*c1)->name->name, (*c2)->name->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world,
|
static int compare_change(const void *p1, const void *p2)
|
||||||
struct apk_package_array **solution, int allow_errors)
|
{
|
||||||
|
const struct apk_change *c1 = (const struct apk_change *) p1;
|
||||||
|
const struct apk_change *c2 = (const struct apk_change *) p2;
|
||||||
|
|
||||||
|
if (c1->newpkg == NULL) {
|
||||||
|
if (c2->newpkg == NULL)
|
||||||
|
/* both deleted - reverse topology order */
|
||||||
|
return pkg_to_ps(c2->oldpkg)->topology_hard -
|
||||||
|
pkg_to_ps(c1->oldpkg)->topology_hard;
|
||||||
|
|
||||||
|
/* c1 deleted, c2 installed -> c2 first*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (c2->newpkg == NULL)
|
||||||
|
/* c1 installed, c2 deleted -> c1 first*/
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return pkg_to_ps(c1->newpkg)->topology_hard -
|
||||||
|
pkg_to_ps(c2->newpkg)->topology_hard;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int generate_changeset(struct apk_database *db,
|
||||||
|
struct apk_package_array *solution,
|
||||||
|
struct apk_changeset *changeset)
|
||||||
|
{
|
||||||
|
struct apk_name *name;
|
||||||
|
struct apk_name_state *ns;
|
||||||
|
struct apk_package *pkg, *pkg0;
|
||||||
|
struct apk_installed_package *ipkg;
|
||||||
|
int i, j, num_installs = 0, num_removed = 0, ci = 0;
|
||||||
|
|
||||||
|
/* calculate change set size */
|
||||||
|
for (i = 0; i < solution->num; i++) {
|
||||||
|
pkg = solution->item[i];
|
||||||
|
if ((pkg->ipkg == NULL) ||
|
||||||
|
(name_to_ns(pkg->name)->solver_flags & APK_SOLVERF_REINSTALL))
|
||||||
|
num_installs++;
|
||||||
|
}
|
||||||
|
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
|
||||||
|
name = ipkg->pkg->name;
|
||||||
|
ns = name_to_ns(name);
|
||||||
|
if ((ns->chosen == NULL) || !(ns->flags & APK_NAMESTF_LOCKED))
|
||||||
|
num_removed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* construct changeset */
|
||||||
|
apk_change_array_resize(&changeset->changes, num_installs + num_removed);
|
||||||
|
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
|
||||||
|
name = ipkg->pkg->name;
|
||||||
|
ns = name_to_ns(name);
|
||||||
|
if ((ns->chosen == NULL) || !(ns->flags & APK_NAMESTF_LOCKED)) {
|
||||||
|
changeset->changes->item[ci].oldpkg = ipkg->pkg;
|
||||||
|
ci++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < solution->num; i++) {
|
||||||
|
pkg = solution->item[i];
|
||||||
|
name = pkg->name;
|
||||||
|
|
||||||
|
if ((pkg->ipkg == NULL) ||
|
||||||
|
(name_to_ns(name)->solver_flags & APK_SOLVERF_REINSTALL)) {
|
||||||
|
for (j = 0; j < name->pkgs->num; j++) {
|
||||||
|
pkg0 = name->pkgs->item[j];
|
||||||
|
if (pkg0->ipkg == NULL)
|
||||||
|
continue;
|
||||||
|
changeset->changes->item[ci].oldpkg = pkg0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
changeset->changes->item[ci].newpkg = pkg;
|
||||||
|
ci++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort changeset to topology order */
|
||||||
|
qsort(changeset->changes->item, changeset->changes->num,
|
||||||
|
sizeof(struct apk_change), compare_change);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int free_state(apk_hash_item item, void *ctx)
|
||||||
|
{
|
||||||
|
struct apk_name *name = (struct apk_name *) item;
|
||||||
|
|
||||||
|
if (name->state_ptr != NULL) {
|
||||||
|
free(name->state_ptr);
|
||||||
|
name->state_ptr = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apk_solver_solve(struct apk_database *db,
|
||||||
|
unsigned short solver_flags,
|
||||||
|
struct apk_dependency_array *world,
|
||||||
|
struct apk_package_array **solution,
|
||||||
|
struct apk_changeset *changeset)
|
||||||
{
|
{
|
||||||
struct apk_solver_state *ss;
|
struct apk_solver_state *ss;
|
||||||
|
struct apk_installed_package *ipkg;
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
ss = calloc(1, sizeof(struct apk_solver_state));
|
ss = calloc(1, sizeof(struct apk_solver_state));
|
||||||
ss->db = db;
|
ss->db = db;
|
||||||
|
ss->solver_flags = solver_flags;
|
||||||
ss->topology_position = -1;
|
ss->topology_position = -1;
|
||||||
ss->best_unsatisfiable = -1;
|
ss->best_unsatisfiable = -1;
|
||||||
ss->allow_errors = allow_errors;
|
|
||||||
list_init(&ss->unsolved_list_head);
|
list_init(&ss->unsolved_list_head);
|
||||||
ss->name_state = calloc(db->available.names.num_items + 1, sizeof(struct apk_name_state));
|
|
||||||
|
|
||||||
for (i = 0; i < world->num; i++)
|
for (i = 0; i < world->num; i++)
|
||||||
sort_name(ss, world->item[i].name);
|
sort_name(ss, world->item[i].name);
|
||||||
|
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list)
|
||||||
|
sort_name(ss, ipkg->pkg->name);
|
||||||
|
|
||||||
foreach_dependency(ss, world, apply_constraint);
|
foreach_dependency(ss, world, apply_constraint);
|
||||||
do {
|
do {
|
||||||
if (ss->allow_errors ||
|
if (ss->cur_unsatisfiable < ss->best_unsatisfiable) {
|
||||||
ss->cur_unsatisfiable < ss->best_unsatisfiable) {
|
|
||||||
r = expand_branch(ss);
|
r = expand_branch(ss);
|
||||||
if (r) {
|
if (r) {
|
||||||
dbg_printf("solution with %d unsatisfiable\n",
|
dbg_printf("solution with %d unsatisfiable\n",
|
||||||
|
@ -677,97 +786,352 @@ int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world
|
||||||
/* collect packages */
|
/* collect packages */
|
||||||
if (r == 0 && ss->cur_unsatisfiable == 0) {
|
if (r == 0 && ss->cur_unsatisfiable == 0) {
|
||||||
record_solution(ss);
|
record_solution(ss);
|
||||||
*solution = ss->best_solution;
|
if (changeset != NULL)
|
||||||
|
generate_changeset(db, ss->best_solution, changeset);
|
||||||
r = 0;
|
r = 0;
|
||||||
} else if (ss->allow_errors) {
|
} else {
|
||||||
*solution = ss->best_solution;
|
|
||||||
qsort(ss->best_solution->item, ss->best_solution->num,
|
qsort(ss->best_solution->item, ss->best_solution->num,
|
||||||
sizeof(struct apk_package *), compare_package_name);
|
sizeof(struct apk_package *), compare_package_name);
|
||||||
r = ss->best_unsatisfiable;
|
r = ss->best_unsatisfiable;
|
||||||
} else
|
}
|
||||||
r = -1;
|
|
||||||
|
|
||||||
free(ss->name_state);
|
if (solution != NULL)
|
||||||
|
*solution = ss->best_solution;
|
||||||
|
else
|
||||||
|
apk_package_array_free(&ss->best_solution);
|
||||||
|
|
||||||
|
apk_hash_foreach(&db->available.names, free_state, NULL);
|
||||||
free(ss);
|
free(ss);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_change(const void *p1, const void *p2)
|
static void print_change(struct apk_database *db,
|
||||||
{
|
struct apk_change *change,
|
||||||
const struct apk_change *c1 = (const struct apk_change *) p1;
|
int cur, int total)
|
||||||
const struct apk_change *c2 = (const struct apk_change *) p2;
|
|
||||||
|
|
||||||
if (c1->newpkg == NULL) {
|
|
||||||
if (c2->newpkg == NULL)
|
|
||||||
/* both deleted - reverse topology order */
|
|
||||||
return pkg_to_ps(c2->oldpkg)->topology_hard -
|
|
||||||
pkg_to_ps(c1->oldpkg)->topology_hard;
|
|
||||||
|
|
||||||
/* c1 deleted, c2 installed -> c2 first*/
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (c2->newpkg == NULL)
|
|
||||||
/* c1 installed, c2 deleted -> c1 first*/
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return pkg_to_ps(c1->newpkg)->topology_hard -
|
|
||||||
pkg_to_ps(c2->newpkg)->topology_hard;
|
|
||||||
}
|
|
||||||
|
|
||||||
int apk_solver_generate_changeset(struct apk_database *db,
|
|
||||||
struct apk_package_array *solution,
|
|
||||||
struct apk_changeset *changeset)
|
|
||||||
{
|
{
|
||||||
struct apk_name *name;
|
struct apk_name *name;
|
||||||
struct apk_package *pkg, *pkg0;
|
struct apk_package *oldpkg = change->oldpkg;
|
||||||
struct apk_installed_package *ipkg;
|
struct apk_package *newpkg = change->newpkg;
|
||||||
int num_installs = 0, num_removed = 0, ci = 0;
|
const char *msg = NULL;
|
||||||
int i, j;
|
char status[64];
|
||||||
|
int r;
|
||||||
|
|
||||||
/* calculate change set size */
|
snprintf(status, sizeof(status), "(%i/%i)", cur+1, total);
|
||||||
for (i = 0; i < solution->num; i++) {
|
status[sizeof(status) - 1] = '\0';
|
||||||
pkg = solution->item[i];
|
|
||||||
name = pkg->name;
|
|
||||||
if (pkg->ipkg == NULL || (name->flags & APK_NAME_REINSTALL))
|
|
||||||
num_installs++;
|
|
||||||
name->flags |= APK_NAME_VISITED;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
|
if (oldpkg != NULL)
|
||||||
if (!(ipkg->pkg->name->flags & APK_NAME_VISITED))
|
name = oldpkg->name;
|
||||||
num_removed++;
|
else
|
||||||
}
|
name = newpkg->name;
|
||||||
|
|
||||||
/* construct changeset */
|
if (oldpkg == NULL) {
|
||||||
apk_change_array_resize(&changeset->changes, num_installs + num_removed);
|
apk_message("%s Installing %s (" BLOB_FMT ")",
|
||||||
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
|
status, name->name,
|
||||||
if (ipkg->pkg->name->flags & APK_NAME_VISITED)
|
BLOB_PRINTF(*newpkg->version));
|
||||||
continue;
|
} else if (newpkg == NULL) {
|
||||||
changeset->changes->item[ci].oldpkg = ipkg->pkg;
|
apk_message("%s Purging %s (" BLOB_FMT ")",
|
||||||
ci++;
|
status, name->name,
|
||||||
}
|
BLOB_PRINTF(*oldpkg->version));
|
||||||
for (i = 0; i < solution->num; i++) {
|
} else {
|
||||||
pkg = solution->item[i];
|
r = apk_pkg_version_compare(newpkg, oldpkg);
|
||||||
name = pkg->name;
|
switch (r) {
|
||||||
|
case APK_VERSION_LESS:
|
||||||
if (pkg->ipkg == NULL || (name->flags & APK_NAME_REINSTALL)) {
|
msg = "Downgrading";
|
||||||
for (j = 0; j < name->pkgs->num; j++) {
|
break;
|
||||||
pkg0 = name->pkgs->item[j];
|
case APK_VERSION_EQUAL:
|
||||||
if (pkg0->ipkg == NULL)
|
if (newpkg == oldpkg)
|
||||||
continue;
|
msg = "Re-installing";
|
||||||
changeset->changes->item[ci].oldpkg = pkg0;
|
else
|
||||||
break;
|
msg = "Replacing";
|
||||||
}
|
break;
|
||||||
changeset->changes->item[ci].newpkg = pkg;
|
case APK_VERSION_GREATER:
|
||||||
ci++;
|
msg = "Upgrading";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
name->flags &= ~APK_NAME_VISITED;
|
apk_message("%s %s %s (" BLOB_FMT " -> " BLOB_FMT ")",
|
||||||
|
status, msg, name->name,
|
||||||
|
BLOB_PRINTF(*oldpkg->version),
|
||||||
|
BLOB_PRINTF(*newpkg->version));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* sort changeset to topology order */
|
struct apk_stats {
|
||||||
qsort(changeset->changes->item, changeset->changes->num,
|
unsigned int bytes;
|
||||||
sizeof(struct apk_change), compare_change);
|
unsigned int packages;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void count_change(struct apk_change *change, struct apk_stats *stats)
|
||||||
|
{
|
||||||
|
if (change->newpkg != NULL) {
|
||||||
|
stats->bytes += change->newpkg->installed_size;
|
||||||
|
stats->packages ++;
|
||||||
|
}
|
||||||
|
if (change->oldpkg != NULL)
|
||||||
|
stats->packages ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_progress(int percent)
|
||||||
|
{
|
||||||
|
const int bar_width = apk_get_screen_width() - 7;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fprintf(stderr, "\e7%3i%% [", percent);
|
||||||
|
for (i = 0; i < bar_width * percent / 100; i++)
|
||||||
|
fputc('#', stderr);
|
||||||
|
for (; i < bar_width; i++)
|
||||||
|
fputc(' ', stderr);
|
||||||
|
fputc(']', stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
fputs("\e8\e[0K", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct progress {
|
||||||
|
struct apk_stats done;
|
||||||
|
struct apk_stats total;
|
||||||
|
struct apk_package *pkg;
|
||||||
|
size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void progress_cb(void *ctx, size_t progress)
|
||||||
|
{
|
||||||
|
struct progress *prog = (struct progress *) ctx;
|
||||||
|
size_t partial = 0, count;
|
||||||
|
|
||||||
|
if (prog->pkg != NULL)
|
||||||
|
partial = muldiv(progress, prog->pkg->installed_size, APK_PROGRESS_SCALE);
|
||||||
|
|
||||||
|
count = muldiv(100, prog->done.bytes + prog->done.packages + partial,
|
||||||
|
prog->total.bytes + prog->total.packages);
|
||||||
|
|
||||||
|
if (prog->count != count)
|
||||||
|
draw_progress(count);
|
||||||
|
prog->count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_packages(struct apk_changeset *changeset,
|
||||||
|
int (*cmp)(struct apk_change *change),
|
||||||
|
const char *msg)
|
||||||
|
{
|
||||||
|
struct apk_change *change;
|
||||||
|
struct apk_name *name;
|
||||||
|
struct apk_indent indent = { 0, 2 };
|
||||||
|
int match = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < changeset->changes->num; i++) {
|
||||||
|
change = &changeset->changes->item[i];
|
||||||
|
if (!cmp(change))
|
||||||
|
continue;
|
||||||
|
if (match == 0)
|
||||||
|
printf("%s:\n ", msg);
|
||||||
|
if (change->newpkg != NULL)
|
||||||
|
name = change->newpkg->name;
|
||||||
|
else
|
||||||
|
name = change->oldpkg->name;
|
||||||
|
|
||||||
|
apk_print_indented(&indent, APK_BLOB_STR(name->name));
|
||||||
|
match++;
|
||||||
|
}
|
||||||
|
if (match)
|
||||||
|
printf("\n");
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_remove(struct apk_change *change)
|
||||||
|
{
|
||||||
|
return change->newpkg == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_new(struct apk_change *change)
|
||||||
|
{
|
||||||
|
return change->oldpkg == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_downgrade(struct apk_change *change)
|
||||||
|
{
|
||||||
|
if (change->newpkg == NULL || change->oldpkg == NULL)
|
||||||
|
return 0;
|
||||||
|
if (apk_pkg_version_compare(change->newpkg, change->oldpkg)
|
||||||
|
& APK_VERSION_LESS)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_upgrade(struct apk_change *change)
|
||||||
|
{
|
||||||
|
if (change->newpkg == NULL || change->oldpkg == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Count swapping package as upgrade too - this can happen if
|
||||||
|
* same package version is used after it was rebuilt against
|
||||||
|
* newer libraries. Basically, different (and probably newer)
|
||||||
|
* package, but equal version number. */
|
||||||
|
if ((apk_pkg_version_compare(change->newpkg, change->oldpkg) &
|
||||||
|
(APK_VERSION_GREATER | APK_VERSION_EQUAL)) &&
|
||||||
|
(change->newpkg != change->oldpkg))
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int commit_changeset(struct apk_database *db,
|
||||||
|
struct apk_changeset *changeset,
|
||||||
|
struct apk_dependency_array *world)
|
||||||
|
{
|
||||||
|
struct progress prog;
|
||||||
|
struct apk_change *change;
|
||||||
|
int i, r = 0, size_diff = 0;
|
||||||
|
|
||||||
|
/* Count what needs to be done */
|
||||||
|
memset(&prog, 0, sizeof(prog));
|
||||||
|
for (i = 0; i < changeset->changes->num; i++) {
|
||||||
|
change = &changeset->changes->item[i];
|
||||||
|
count_change(change, &prog.total);
|
||||||
|
if (change->newpkg)
|
||||||
|
size_diff += change->newpkg->installed_size;
|
||||||
|
if (change->oldpkg)
|
||||||
|
size_diff -= change->oldpkg->installed_size;
|
||||||
|
}
|
||||||
|
size_diff /= 1024;
|
||||||
|
|
||||||
|
if (apk_verbosity > 1 || (apk_flags & APK_INTERACTIVE)) {
|
||||||
|
r = dump_packages(changeset, cmp_remove,
|
||||||
|
"The following packages will be REMOVED");
|
||||||
|
r += dump_packages(changeset, cmp_downgrade,
|
||||||
|
"The following packages will be DOWNGRADED");
|
||||||
|
if (r || (apk_flags & APK_INTERACTIVE) || apk_verbosity > 2) {
|
||||||
|
dump_packages(changeset, cmp_new,
|
||||||
|
"The following NEW packages will be installed");
|
||||||
|
dump_packages(changeset, cmp_upgrade,
|
||||||
|
"The following packages will be upgraded");
|
||||||
|
printf("After this operation, %d kB of %s\n", abs(size_diff),
|
||||||
|
(size_diff < 0) ?
|
||||||
|
"disk space will be freed." :
|
||||||
|
"additional disk space will be used.");
|
||||||
|
}
|
||||||
|
if (apk_flags & APK_INTERACTIVE) {
|
||||||
|
printf("Do you want to continue [Y/n]? ");
|
||||||
|
fflush(stdout);
|
||||||
|
r = fgetc(stdin);
|
||||||
|
if (r != 'y' && r != 'Y' && r != '\n')
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go through changes */
|
||||||
|
r = 0;
|
||||||
|
for (i = 0; i < changeset->changes->num; i++) {
|
||||||
|
change = &changeset->changes->item[i];
|
||||||
|
|
||||||
|
print_change(db, change, i, changeset->changes->num);
|
||||||
|
if (apk_flags & APK_PROGRESS)
|
||||||
|
draw_progress(prog.count);
|
||||||
|
prog.pkg = change->newpkg;
|
||||||
|
|
||||||
|
if (!(apk_flags & APK_SIMULATE)) {
|
||||||
|
r = apk_db_install_pkg(db,
|
||||||
|
change->oldpkg, change->newpkg,
|
||||||
|
(apk_flags & APK_PROGRESS) ? progress_cb : NULL,
|
||||||
|
&prog);
|
||||||
|
if (r != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_change(change, &prog.done);
|
||||||
|
}
|
||||||
|
if (apk_flags & APK_PROGRESS)
|
||||||
|
draw_progress(100);
|
||||||
|
|
||||||
|
apk_db_run_triggers(db);
|
||||||
|
|
||||||
|
apk_dependency_array_copy(&db->world, world);
|
||||||
|
apk_db_write_config(db);
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
apk_message("OK: %d packages, %d dirs, %d files",
|
||||||
|
db->installed.stats.packages,
|
||||||
|
db->installed.stats.dirs,
|
||||||
|
db->installed.stats.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_dep_errors(char *label, struct apk_dependency_array *deps)
|
||||||
|
{
|
||||||
|
int i, print_label = 1;
|
||||||
|
char buf[256];
|
||||||
|
apk_blob_t p;
|
||||||
|
struct apk_indent indent;
|
||||||
|
|
||||||
|
for (i = 0; i < deps->num; i++) {
|
||||||
|
struct apk_dependency *dep = &deps->item[i];
|
||||||
|
struct apk_package *pkg = (struct apk_package*) dep->name->state_ptr;
|
||||||
|
|
||||||
|
if (pkg != NULL && apk_dep_is_satisfied(dep, pkg))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (print_label) {
|
||||||
|
print_label = 0;
|
||||||
|
indent.x = printf(" %s:", label);
|
||||||
|
indent.indent = indent.x + 1;
|
||||||
|
}
|
||||||
|
p = APK_BLOB_BUF(buf);
|
||||||
|
apk_blob_push_dep(&p, dep);
|
||||||
|
p = apk_blob_pushed(APK_BLOB_BUF(buf), p);
|
||||||
|
apk_print_indented(&indent, p);
|
||||||
|
}
|
||||||
|
if (!print_label)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_errors(struct apk_database *db,
|
||||||
|
struct apk_package_array *solution,
|
||||||
|
struct apk_dependency_array *world,
|
||||||
|
int unsatisfiable)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
apk_error("%d unsatisfiable dependencies:", unsatisfiable);
|
||||||
|
|
||||||
|
for (i = 0; i < solution->num; i++) {
|
||||||
|
struct apk_package *pkg = solution->item[i];
|
||||||
|
pkg->name->state_ptr = pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_dep_errors("world", world);
|
||||||
|
for (i = 0; i < solution->num; i++) {
|
||||||
|
struct apk_package *pkg = solution->item[i];
|
||||||
|
char pkgtext[256];
|
||||||
|
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i]));
|
||||||
|
print_dep_errors(pkgtext, pkg->depends);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int apk_solver_commit(struct apk_database *db,
|
||||||
|
unsigned short solver_flags,
|
||||||
|
struct apk_dependency_array *world)
|
||||||
|
{
|
||||||
|
struct apk_changeset changeset = {};
|
||||||
|
struct apk_package_array *solution = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = apk_solver_solve(db, solver_flags, world, &solution, &changeset);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (changeset.changes == NULL)
|
||||||
|
apk_change_array_init(&changeset.changes);
|
||||||
|
|
||||||
|
if (r == 0 || (apk_flags & APK_FORCE)) {
|
||||||
|
/* Success -- or forced installation of bad graph */
|
||||||
|
commit_changeset(db, &changeset, world);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
/* Failure -- print errors */
|
||||||
|
print_errors(db, solution, world, r);
|
||||||
|
}
|
||||||
|
apk_package_array_free(&solution);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
1059
src/state.c
1059
src/state.c
File diff suppressed because it is too large
Load Diff
|
@ -14,15 +14,21 @@
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_database.h"
|
#include "apk_database.h"
|
||||||
#include "apk_state.h"
|
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
#include "apk_solver.h"
|
||||||
|
|
||||||
|
struct upgrade_ctx {
|
||||||
|
unsigned short solver_flags;
|
||||||
|
};
|
||||||
|
|
||||||
static int upgrade_parse(void *ctx, struct apk_db_options *dbopts,
|
static int upgrade_parse(void *ctx, struct apk_db_options *dbopts,
|
||||||
int optch, int optindex, const char *optarg)
|
int optch, int optindex, const char *optarg)
|
||||||
{
|
{
|
||||||
|
struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx;
|
||||||
|
|
||||||
switch (optch) {
|
switch (optch) {
|
||||||
case 'a':
|
case 'a':
|
||||||
apk_flags |= APK_PREFER_AVAILABLE;
|
uctx->solver_flags |= APK_SOLVERF_AVAILABLE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -30,8 +36,10 @@ static int upgrade_parse(void *ctx, struct apk_db_options *dbopts,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_do_self_upgrade(struct apk_database *db, struct apk_state *state)
|
int apk_do_self_upgrade(struct apk_database *db)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
/* FIXME: Reimplement self-upgrade. */
|
||||||
struct apk_dependency dep;
|
struct apk_dependency dep;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -57,58 +65,24 @@ int apk_do_self_upgrade(struct apk_database *db, struct apk_state *state)
|
||||||
|
|
||||||
apk_error("PANIC! Failed to re-execute new apk-tools!");
|
apk_error("PANIC! Failed to re-execute new apk-tools!");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct apk_state *state = NULL;
|
struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx;
|
||||||
struct apk_name_array *missing;
|
unsigned short solver_flags;
|
||||||
int i, r = 0;
|
int r;
|
||||||
|
|
||||||
apk_flags |= APK_UPGRADE;
|
solver_flags = APK_SOLVERF_UPGRADE | uctx->solver_flags;
|
||||||
apk_name_array_init(&missing);
|
|
||||||
|
|
||||||
state = apk_state_new(db);
|
r = apk_do_self_upgrade(db);
|
||||||
if (state == NULL)
|
if (r != 0)
|
||||||
goto err;
|
return r;
|
||||||
|
|
||||||
r = apk_do_self_upgrade(db, state);
|
return apk_solver_commit(db, solver_flags, db->world);
|
||||||
if (r != 0) {
|
|
||||||
apk_state_print_errors(state);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < db->world->num; i++) {
|
|
||||||
struct apk_dependency *dep = &db->world->item[i];
|
|
||||||
|
|
||||||
if (dep->name->pkgs->num != 0)
|
|
||||||
r |= apk_state_lock_dependency(state, dep);
|
|
||||||
else
|
|
||||||
*apk_name_array_add(&missing) = dep->name;
|
|
||||||
}
|
|
||||||
if (r == 0) {
|
|
||||||
for (i = 0; i < missing->num; i++) {
|
|
||||||
struct apk_indent indent;
|
|
||||||
struct apk_name *name = missing->item[i];
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
apk_warning("The following package names no longer exists in repository:");
|
|
||||||
indent.x = 0;
|
|
||||||
indent.indent = 2;
|
|
||||||
}
|
|
||||||
apk_print_indented(&indent, APK_BLOB_STR(name->name));
|
|
||||||
}
|
|
||||||
if (i != 0)
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
r = apk_state_commit(state);
|
|
||||||
} else
|
|
||||||
apk_state_print_errors(state);
|
|
||||||
err:
|
|
||||||
if (state != NULL)
|
|
||||||
apk_state_unref(state);
|
|
||||||
apk_name_array_free(&missing);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct apk_option upgrade_options[] = {
|
static struct apk_option upgrade_options[] = {
|
||||||
|
|
Loading…
Reference in New Issue