Commit a23f6f4a authored by Timo Teräs's avatar Timo Teräs

state: rework changeset calculation algorithm

Calculate changesets directly by stabilizating the package graph instead of
recalculating the whole graph and then diffing (similar approach as seen
in 'smart' package manager). The algorithm is not complete: defferred
search space forking is missing. So you don't always get a solution on
complex graphs.

Benefits:
- usually the search state tree is smaller (less memory used)
- speed relational to changeset size, not database size (usually faster)
- touch only packages related to users request (can work on partitially
  broken state; upgrades only necessary packages, fixes #7)

Also implemented:
- command prompt to confirm operation if packages are deleted or downgraded
- requesting deletion of package suggests removal of all packages depending
  on the package being removed (you'll get list of packages that also get
  removed if you want package X removed)
- option --simulate to see what would have been done (mainly for testing)
- an untested implementation of versioned dependencies and conflicts

A lot has changed, so expect new bugs too.
parent 7cef96c3
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#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"
struct add_ctx { struct add_ctx {
unsigned int open_flags; unsigned int open_flags;
...@@ -27,7 +28,7 @@ static int add_parse(void *ctx, int optch, int optindex, const char *optarg) ...@@ -27,7 +28,7 @@ static int add_parse(void *ctx, int optch, int optindex, const char *optarg)
actx->open_flags |= APK_OPENF_CREATE; actx->open_flags |= APK_OPENF_CREATE;
break; break;
case 'u': case 'u':
apk_upgrade = 1; apk_flags |= APK_UPGRADE;
break; break;
default: default:
return -1; return -1;
...@@ -39,12 +40,14 @@ static int add_main(void *ctx, int argc, char **argv) ...@@ -39,12 +40,14 @@ static int add_main(void *ctx, int argc, char **argv)
{ {
struct add_ctx *actx = (struct add_ctx *) ctx; struct add_ctx *actx = (struct add_ctx *) ctx;
struct apk_database db; struct apk_database db;
int i, r, ret = 1; struct apk_state *state;
int i, r;
r = apk_db_open(&db, apk_root, actx->open_flags | APK_OPENF_WRITE); r = apk_db_open(&db, apk_root, actx->open_flags | APK_OPENF_WRITE);
if (r != 0) if (r != 0)
return r; return r;
state = apk_state_new(&db);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
struct apk_dependency dep; struct apk_dependency dep;
...@@ -59,20 +62,29 @@ static int add_main(void *ctx, int argc, char **argv) ...@@ -59,20 +62,29 @@ static int add_main(void *ctx, int argc, char **argv)
dep = (struct apk_dependency) { dep = (struct apk_dependency) {
.name = pkg->name, .name = pkg->name,
.min_version = pkg->version, .version = pkg->version,
.max_version = pkg->version, .result_mask = APK_VERSION_EQUAL,
}; };
} else { } else {
dep = (struct apk_dependency) { dep = (struct apk_dependency) {
.name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])), .name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])),
.result_mask = APK_DEPMASK_REQUIRE,
}; };
} }
apk_deps_add(&db.world, &dep); apk_deps_add(&db.world, &dep);
dep.name->flags |= APK_NAME_TOPLEVEL;
r = apk_state_lock_dependency(state, &dep);
if (r != 0) {
apk_error("Unable to install '%s'", dep.name->name);
goto err;
}
} }
ret = apk_db_recalculate_and_commit(&db); r = apk_state_commit(state, &db);
err: err:
apk_state_unref(state);
apk_db_close(&db); apk_db_close(&db);
return ret; return r;
} }
static struct option add_options[] = { static struct option add_options[] = {
......
...@@ -23,9 +23,8 @@ ...@@ -23,9 +23,8 @@
const char *apk_root; const char *apk_root;
struct apk_repository_url apk_repository_list; struct apk_repository_url apk_repository_list;
int apk_verbosity = 1, apk_progress = 0, apk_upgrade = 0; int apk_verbosity = 1, apk_cwd_fd;
int apk_clean = 0, apk_force = 0; unsigned int apk_flags = 0;
int apk_cwd_fd;
void apk_log(const char *prefix, const char *format, ...) void apk_log(const char *prefix, const char *format, ...)
{ {
...@@ -111,16 +110,17 @@ static struct apk_repository_url *apk_repository_new(const char *url) ...@@ -111,16 +110,17 @@ static struct apk_repository_url *apk_repository_new(const char *url)
return r; return r;
} }
#define NUM_GENERIC_OPTS 8 #define NUM_GENERIC_OPTS 9
static struct option generic_options[32] = { static struct option generic_options[32] = {
{ "root", required_argument, NULL, 'p' }, { "root", required_argument, NULL, 'p' },
{ "repository", required_argument, NULL, 'X' }, { "repository", required_argument, NULL, 'X' },
{ "quiet", no_argument, NULL, 'q' }, { "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "progress", no_argument, &apk_progress, 1 }, { "progress", no_argument, NULL, 0x101 },
{ "clean-protected", no_argument, &apk_clean, 1 }, { "clean-protected", no_argument, NULL, 0x102 },
{ "force", no_argument, &apk_force, 1 }, { "force", no_argument, NULL, 0x103 },
{ "simulate", no_argument, NULL, 0x104 },
}; };
int main(int argc, char **argv) int main(int argc, char **argv)
...@@ -181,6 +181,17 @@ int main(int argc, char **argv) ...@@ -181,6 +181,17 @@ int main(int argc, char **argv)
break; break;
case 'V': case 'V':
return version(); return version();
case 0x101:
apk_flags |= APK_PROGRESS;
break;
case 0x102:
apk_flags |= APK_CLEAN_PROTECTED;
break;
case 0x103:
apk_flags |= APK_FORCE;
break;
case 0x104:
apk_flags |= APK_SIMULATE;
break; break;
default: default:
if (applet == NULL || applet->parse == NULL) if (applet == NULL || applet->parse == NULL)
......
...@@ -54,8 +54,12 @@ struct apk_db_dir_instance { ...@@ -54,8 +54,12 @@ struct apk_db_dir_instance {
gid_t gid; gid_t gid;
}; };
#define APK_NAME_TOPLEVEL 0x0001
struct apk_name { struct apk_name {
apk_hash_node hash_node; apk_hash_node hash_node;
unsigned int id;
unsigned int flags;
char *name; char *name;
struct apk_package_array *pkgs; struct apk_package_array *pkgs;
struct apk_name_array *rdepends; struct apk_name_array *rdepends;
...@@ -68,7 +72,7 @@ struct apk_repository { ...@@ -68,7 +72,7 @@ struct apk_repository {
struct apk_database { struct apk_database {
char *root; char *root;
int root_fd, lock_fd; int root_fd, lock_fd;
unsigned pkg_id, num_repos; unsigned name_id, num_repos;
struct apk_dependency_array *world; struct apk_dependency_array *world;
struct apk_string_array *protected_paths; struct apk_string_array *protected_paths;
...@@ -109,6 +113,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, ...@@ -109,6 +113,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
#define APK_OPENF_CREATE 0x0002 #define APK_OPENF_CREATE 0x0002
int apk_db_open(struct apk_database *db, const char *root, unsigned int flags); int apk_db_open(struct apk_database *db, const char *root, unsigned int flags);
int apk_db_write_config(struct apk_database *db);
void apk_db_close(struct apk_database *db); void apk_db_close(struct apk_database *db);
struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *file); struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *file);
...@@ -118,8 +123,6 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db, apk_blob_t fi ...@@ -118,8 +123,6 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db, apk_blob_t fi
int apk_db_index_write(struct apk_database *db, struct apk_ostream *os); int apk_db_index_write(struct apk_database *db, struct apk_ostream *os);
int apk_db_add_repository(apk_database_t db, apk_blob_t repository); int apk_db_add_repository(apk_database_t db, apk_blob_t repository);
int apk_db_recalculate_and_commit(struct apk_database *db);
int apk_db_install_pkg(struct apk_database *db, int apk_db_install_pkg(struct apk_database *db,
struct apk_package *oldpkg, struct apk_package *oldpkg,
struct apk_package *newpkg, struct apk_package *newpkg,
......
...@@ -50,8 +50,14 @@ extern csum_t bad_checksum; ...@@ -50,8 +50,14 @@ extern csum_t bad_checksum;
#define csum_valid(buf) memcmp(buf, bad_checksum, sizeof(csum_t)) #define csum_valid(buf) memcmp(buf, bad_checksum, sizeof(csum_t))
#endif #endif
extern int apk_cwd_fd, apk_verbosity, apk_progress, apk_upgrade; extern int apk_cwd_fd, apk_verbosity;
extern int apk_clean, apk_force; extern unsigned int apk_flags;
#define APK_FORCE 0x0001
#define APK_SIMULATE 0x0002
#define APK_CLEAN_PROTECTED 0x0004
#define APK_PROGRESS 0x0008
#define APK_UPGRADE 0x0010
#define apk_error(args...) apk_log("ERROR: ", args); #define apk_error(args...) apk_log("ERROR: ", args);
#define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); } #define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); }
......
...@@ -28,6 +28,9 @@ struct apk_name; ...@@ -28,6 +28,9 @@ struct apk_name;
#define APK_SCRIPT_PRE_UPGRADE 5 #define APK_SCRIPT_PRE_UPGRADE 5
#define APK_SCRIPT_POST_UPGRADE 6 #define APK_SCRIPT_POST_UPGRADE 6
#define APK_PKG_NOT_INSTALLED 0
#define APK_PKG_INSTALLED 1
struct apk_script { struct apk_script {
struct hlist_node script_list; struct hlist_node script_list;
unsigned int type; unsigned int type;
...@@ -35,10 +38,14 @@ struct apk_script { ...@@ -35,10 +38,14 @@ struct apk_script {
char script[]; char script[];
}; };
#define APK_DEPMASK_REQUIRE (APK_VERSION_EQUAL|APK_VERSION_LESS|\
APK_VERSION_GREATER)
#define APK_DEPMASK_CONFLICT (0)
struct apk_dependency { struct apk_dependency {
struct apk_name *name; struct apk_name *name;
char *min_version; int result_mask;
char *max_version; char *version;
}; };
APK_ARRAY(apk_dependency_array, struct apk_dependency); APK_ARRAY(apk_dependency_array, struct apk_dependency);
...@@ -46,7 +53,7 @@ struct apk_package { ...@@ -46,7 +53,7 @@ struct apk_package {
apk_hash_node hash_node; apk_hash_node hash_node;
csum_t csum; csum_t csum;
unsigned id, repos; unsigned repos;
struct apk_name *name; struct apk_name *name;
char *version; char *version;
char *url, *description, *license; char *url, *description, *license;
......
...@@ -14,43 +14,17 @@ ...@@ -14,43 +14,17 @@
#include "apk_database.h" #include "apk_database.h"
#define APK_STATE_NOT_CONSIDERED 0 struct apk_state;
#define APK_STATE_INSTALL 1
#define APK_STATE_NO_INSTALL 2
struct apk_change {
struct list_head change_list;
struct apk_package *oldpkg;
struct apk_package *newpkg;
};
struct apk_state {
int refs;
struct list_head change_list_head;
unsigned char bitarray[];
};
struct apk_deferred_state {
unsigned int preference;
struct apk_package *deferred_install;
/* struct apk_pkg_name_queue *install_queue; */
struct apk_state *state;
};
struct apk_state *apk_state_new(struct apk_database *db); struct apk_state *apk_state_new(struct apk_database *db);
struct apk_state *apk_state_dup(struct apk_state *state); struct apk_state *apk_state_dup(struct apk_state *state);
void apk_state_unref(struct apk_state *state); void apk_state_unref(struct apk_state *state);
int apk_state_commit(struct apk_state *state, struct apk_database *db); int apk_state_commit(struct apk_state *state, struct apk_database *db);
int apk_state_lock_dependency(struct apk_state *state,
int apk_state_satisfy_deps(struct apk_state *state, struct apk_dependency *dep);
struct apk_dependency_array *deps); int apk_state_lock_name(struct apk_state *state,
int apk_state_purge_unneeded(struct apk_state *state, struct apk_name *name,
struct apk_database *db); struct apk_package *newpkg);
int apk_state_pkg_install(struct apk_state *state,
struct apk_package *pkg);
int apk_state_pkg_is_installed(struct apk_state *state,
struct apk_package *pkg);
#endif #endif
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include "apk_blob.h" #include "apk_blob.h"
#define APK_VERSION_LESS -1 #define APK_VERSION_EQUAL 1
#define APK_VERSION_EQUAL 0 #define APK_VERSION_LESS 2
#define APK_VERSION_GREATER 1 #define APK_VERSION_GREATER 4
#define APK_VERSION_RESULT_MASK(r) (1 << ((r)+1))
int apk_version_validate(apk_blob_t ver); int apk_version_validate(apk_blob_t ver);
int apk_version_compare(apk_blob_t a, apk_blob_t b); int apk_version_compare(apk_blob_t a, apk_blob_t b);
......
...@@ -154,6 +154,7 @@ struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name) ...@@ -154,6 +154,7 @@ 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_hash_insert(&db->available.names, pn); apk_hash_insert(&db->available.names, pn);
return pn; return pn;
...@@ -355,7 +356,6 @@ static struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_pa ...@@ -355,7 +356,6 @@ static struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_pa
idb = apk_hash_get(&db->available.packages, APK_BLOB_BUF(pkg->csum)); idb = apk_hash_get(&db->available.packages, APK_BLOB_BUF(pkg->csum));
if (idb == NULL) { if (idb == NULL) {
idb = pkg; idb = pkg;
pkg->id = db->pkg_id++;
apk_hash_insert(&db->available.packages, pkg); apk_hash_insert(&db->available.packages, pkg);
*apk_package_array_add(&pkg->name->pkgs) = pkg; *apk_package_array_add(&pkg->name->pkgs) = pkg;
apk_db_pkg_rdepends(db, pkg); apk_db_pkg_rdepends(db, pkg);
...@@ -393,7 +393,7 @@ static int apk_db_index_read(struct apk_database *db, struct apk_istream *is, in ...@@ -393,7 +393,7 @@ static int apk_db_index_read(struct apk_database *db, struct apk_istream *is, in
if (repo != -1) if (repo != -1)
pkg->repos |= BIT(repo); pkg->repos |= BIT(repo);
else else
apk_pkg_set_state(db, pkg, APK_STATE_INSTALL); apk_pkg_set_state(db, pkg, APK_PKG_INSTALLED);
if (apk_db_pkg_add(db, pkg) != pkg && repo == -1) { if (apk_db_pkg_add(db, pkg) != pkg && repo == -1) {
apk_error("Installed database load failed"); apk_error("Installed database load failed");
...@@ -573,6 +573,7 @@ static int apk_db_read_state(struct apk_database *db) ...@@ -573,6 +573,7 @@ static int apk_db_read_state(struct apk_database *db)
{ {
struct apk_istream *is; struct apk_istream *is;
apk_blob_t blob; apk_blob_t blob;
int i;
/* Read: /* Read:
* 1. installed repository * 1. installed repository
...@@ -590,6 +591,9 @@ static int apk_db_read_state(struct apk_database *db) ...@@ -590,6 +591,9 @@ static int apk_db_read_state(struct apk_database *db)
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;
is = apk_istream_from_file("var/lib/apk/installed"); is = apk_istream_from_file("var/lib/apk/installed");
if (is != NULL) { if (is != NULL) {
apk_db_index_read(db, is, -1); apk_db_index_read(db, is, -1);
...@@ -742,7 +746,7 @@ struct write_ctx { ...@@ -742,7 +746,7 @@ struct write_ctx {
int fd; int fd;
}; };
static int apk_db_write_config(struct apk_database *db) int apk_db_write_config(struct apk_database *db)
{ {
struct apk_ostream *os; struct apk_ostream *os;
...@@ -919,39 +923,6 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository) ...@@ -919,39 +923,6 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
return 0; return 0;
} }
int apk_db_recalculate_and_commit(struct apk_database *db)
{
struct apk_state *state;
int r;
state = apk_state_new(db);
r = apk_state_satisfy_deps(state, db->world);
if (r == 0) {
r = apk_state_purge_unneeded(state, db);
if (r != 0) {
apk_error("Failed to clean up state");
return r;
}
r = apk_state_commit(state, db);
if (r != 0) {
apk_error("Failed to commit changes");
return r;
}
apk_db_write_config(db);
apk_message("OK: %d packages, %d dirs, %d files",
db->installed.stats.packages,
db->installed.stats.dirs,
db->installed.stats.files);
} else {
apk_error("Failed to build installation graph");
}
apk_state_unref(state);
return r;
}
static void extract_cb(void *_ctx, size_t progress) static void extract_cb(void *_ctx, size_t progress)
{ {
struct install_ctx *ctx = (struct install_ctx *) _ctx; struct install_ctx *ctx = (struct install_ctx *) _ctx;
...@@ -1069,7 +1040,7 @@ static int apk_db_install_archive_entry(void *_ctx, ...@@ -1069,7 +1040,7 @@ static int apk_db_install_archive_entry(void *_ctx,
if (file->diri != diri) { if (file->diri != diri) {
opkg = file->diri->pkg; opkg = file->diri->pkg;
if (opkg->name != pkg->name) { if (opkg->name != pkg->name) {
if (!apk_force) { if (!(apk_flags & APK_FORCE)) {
apk_error("%s: Trying to overwrite %s " apk_error("%s: Trying to overwrite %s "
"owned by %s.\n", "owned by %s.\n",
pkg->name->name, ae->name, pkg->name->name, ae->name,
...@@ -1093,7 +1064,7 @@ static int apk_db_install_archive_entry(void *_ctx, ...@@ -1093,7 +1064,7 @@ static int apk_db_install_archive_entry(void *_ctx,
(memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0 || (memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0 ||
!csum_valid(file->csum))) { !csum_valid(file->csum))) {
/* Protected file. Extract to separate place */ /* Protected file. Extract to separate place */
if (!apk_clean) { if (!(apk_flags & APK_CLEAN_PROTECTED)) {
snprintf(alt_name, sizeof(alt_name), snprintf(alt_name, sizeof(alt_name),
"%s/%s.apk-new", "%s/%s.apk-new",
diri->dir->dirname, file->filename); diri->dir->dirname, file->filename);
...@@ -1160,7 +1131,7 @@ static void apk_db_purge_pkg(struct apk_database *db, ...@@ -1160,7 +1131,7 @@ static void apk_db_purge_pkg(struct apk_database *db,
__hlist_del(dc, &pkg->owned_dirs.first); __hlist_del(dc, &pkg->owned_dirs.first);
apk_db_diri_free(db, diri); apk_db_diri_free(db, diri);
} }
apk_pkg_set_state(db, pkg, APK_STATE_NO_INSTALL); apk_pkg_set_state(db, pkg, APK_PKG_NOT_INSTALLED);
} }
int apk_db_install_pkg(struct apk_database *db, int apk_db_install_pkg(struct apk_database *db,
...@@ -1229,7 +1200,7 @@ int apk_db_install_pkg(struct apk_database *db, ...@@ -1229,7 +1200,7 @@ int apk_db_install_pkg(struct apk_database *db,
bs->close(bs, csum, NULL); bs->close(bs, csum, NULL);
apk_pkg_set_state(db, newpkg, APK_STATE_INSTALL); apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED);
if (memcmp(csum, newpkg->csum, sizeof(csum)) != 0) if (memcmp(csum, newpkg->csum, sizeof(csum)) != 0)
apk_warning("%s-%s: checksum does not match", apk_warning("%s-%s: checksum does not match",
......
...@@ -11,12 +11,15 @@ ...@@ -11,12 +11,15 @@
#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"
static int del_main(void *ctx, int argc, char **argv) static int del_main(void *ctx, int argc, char **argv)
{ {
struct apk_database db; struct apk_database db;
int i, j; struct apk_state *state;
struct apk_name *name;
int i, j, r;
if (apk_db_open(&db, apk_root, APK_OPENF_WRITE) < 0) if (apk_db_open(&db, apk_root, APK_OPENF_WRITE) < 0)
return -1; return -1;
...@@ -24,7 +27,13 @@ static int del_main(void *ctx, int argc, char **argv) ...@@ -24,7 +27,13 @@ static int del_main(void *ctx, int argc, char **argv)
if (db.world == NULL) if (db.world == NULL)
goto out; goto out;
state = apk_state_new(&db);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
struct apk_dependency dep;
name = apk_db_get_name(&db, APK_BLOB_STR(argv[i]));
/* Remove from world, so we get proper changeset */
for (j = 0; j < db.world->num; j++) { for (j = 0; j < db.world->num; j++) {
if (strcmp(db.world->item[j].name->name, if (strcmp(db.world->item[j].name->name,
argv[i]) == 0) { argv[i]) == 0) {
...@@ -34,13 +43,26 @@ static int del_main(void *ctx, int argc, char **argv) ...@@ -34,13 +43,26 @@ static int del_main(void *ctx, int argc, char **argv)
apk_dependency_array_resize(db.world, db.world->num-1); apk_dependency_array_resize(db.world, db.world->num-1);
} }
} }
} name->flags &= ~APK_NAME_TOPLEVEL;
apk_db_recalculate_and_commit(&db); dep = (struct apk_dependency) {
.name = name,
.result_mask = APK_DEPMASK_CONFLICT,
};
r = apk_state_lock_dependency(state, &dep);
if (r != 0) {
apk_error("Unable to remove '%s'", name->name);
goto err;
}
}
r = apk_state_commit(state, &db);
err:
apk_state_unref(state);
out: out:
apk_db_close(&db); apk_db_close(&db);
return 0; return r;
} }
static struct apk_applet apk_del = { static struct apk_applet apk_del = {
......
...@@ -50,7 +50,7 @@ static int info_exists(struct info_ctx *ctx, struct apk_database *db, ...@@ -50,7 +50,7 @@ static int info_exists(struct info_ctx *ctx, struct apk_database *db,
return 1; return 1;
for (j = 0; j < name->pkgs->num; j++) { for (j = 0; j < name->pkgs->num; j++) {
if (apk_pkg_get_state(name->pkgs->item[j]) == APK_STATE_INSTALL) if (apk_pkg_get_state(name->pkgs->item[j]) == APK_PKG_INSTALLED)
break; break;
} }
if (j >= name->pkgs->num) if (j >= name->pkgs->num)
...@@ -76,6 +76,7 @@ static int info_who_owns(struct info_ctx *ctx, struct apk_database *db, ...@@ -76,6 +76,7 @@ static int info_who_owns(struct info_ctx *ctx, struct apk_database *db,
if (apk_verbosity < 1) { if (apk_verbosity < 1) {
dep = (struct apk_dependency) { dep = (struct apk_dependency) {
.name = pkg->name,