commit.c 18.9 KB
Newer Older
1
2
3
4
5
6
/* commit.c - Alpine Package Keeper (APK)
 * Apply solver calculated changes to database.
 *
 * Copyright (C) 2008-2013 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
7
 * SPDX-License-Identifier: GPL-2.0-only
8
9
 */

10
#include <assert.h>
11
#include <limits.h>
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdint.h>
#include <unistd.h>
#include "apk_defines.h"
#include "apk_database.h"
#include "apk_package.h"
#include "apk_solver.h"

#include "apk_print.h"

static inline int pkg_available(struct apk_database *db, struct apk_package *pkg)
{
	if (pkg->repos & db->available_repos)
		return TRUE;
	return FALSE;
}

static int print_change(struct apk_database *db, struct apk_change *change,
			int cur, int total)
{
31
	struct apk_out *out = &db->ctx->out;
32
33
34
35
	struct apk_name *name;
	struct apk_package *oldpkg = change->old_pkg;
	struct apk_package *newpkg = change->new_pkg;
	const char *msg = NULL;
36
	char status[32];
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
	apk_blob_t *oneversion = NULL;
	int r;

	snprintf(status, sizeof(status), "(%i/%i)", cur+1, total);

	name = newpkg ? newpkg->name : oldpkg->name;
	if (oldpkg == NULL) {
		msg = "Installing";
		oneversion = newpkg->version;
	} else if (newpkg == NULL) {
		msg = "Purging";
		oneversion = oldpkg->version;
	} else if (newpkg == oldpkg) {
		if (change->reinstall) {
			if (pkg_available(db, newpkg))
52
				msg = "Reinstalling";
53
			else
54
				msg = "[APK unavailable, skipped] Reinstalling";
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
		} else if (change->old_repository_tag != change->new_repository_tag) {
			msg = "Updating pinning";
		}
		oneversion = newpkg->version;
	} else {
		r = apk_pkg_version_compare(newpkg, oldpkg);
		switch (r) {
		case APK_VERSION_LESS:
			msg = "Downgrading";
			break;
		case APK_VERSION_EQUAL:
			msg = "Replacing";
			break;
		case APK_VERSION_GREATER:
			msg = "Upgrading";
			break;
		}
	}
	if (msg == NULL)
		return FALSE;

	if (oneversion) {
77
78
79
80
81
		apk_msg(out, "%s %s %s" BLOB_FMT " (" BLOB_FMT ")",
			status, msg,
			name->name,
			BLOB_PRINTF(db->repo_tags[change->new_repository_tag].tag),
			BLOB_PRINTF(*oneversion));
82
	} else {
83
84
85
86
87
88
		apk_msg(out, "%s %s %s" BLOB_FMT " (" BLOB_FMT " -> " BLOB_FMT ")",
			status, msg,
			name->name,
			BLOB_PRINTF(db->repo_tags[change->new_repository_tag].tag),
			BLOB_PRINTF(*oldpkg->version),
			BLOB_PRINTF(*newpkg->version));
89
90
91
92
93
94
	}
	return TRUE;
}

struct apk_stats {
	unsigned int changes;
95
	size_t bytes;
96
97
98
99
100
	unsigned int packages;
};

static void count_change(struct apk_change *change, struct apk_stats *stats)
{
101
	if (change->new_pkg != change->old_pkg || change->reinstall) {
102
103
		if (change->new_pkg != NULL) {
			stats->bytes += change->new_pkg->installed_size;
104
			stats->packages++;
105
106
		}
		if (change->old_pkg != NULL)
107
			stats->packages++;
108
		stats->changes++;
109
110
	} else if (change->new_repository_tag != change->old_repository_tag) {
		stats->packages++;
111
112
113
114
115
		stats->changes++;
	}
}

struct progress {
116
	struct apk_progress prog;
117
118
119
120
121
	struct apk_stats done;
	struct apk_stats total;
	struct apk_package *pkg;
};

122
static void progress_cb(void *ctx, size_t installed_bytes)
123
124
{
	struct progress *prog = (struct progress *) ctx;
125
126
	apk_print_progress(&prog->prog,
			   prog->done.bytes + prog->done.packages + installed_bytes,
127
			   prog->total.bytes + prog->total.packages);
128
129
}

130
static int dump_packages(struct apk_out *out, struct apk_changeset *changeset,
131
132
133
134
135
			 int (*cmp)(struct apk_change *change),
			 const char *msg)
{
	struct apk_change *change;
	struct apk_name *name;
136
	struct apk_indent indent;
137
	int match = 0;
138

139
	apk_print_indented_init(&indent, out, 0);
140
	foreach_array_item(change, changeset->changes) {
141
142
		if (!cmp(change)) continue;
		if (!match) apk_print_indented_group(&indent, 2, "%s:\n", msg);
143
144
145
146
147
148
149
150
		if (change->new_pkg != NULL)
			name = change->new_pkg->name;
		else
			name = change->old_pkg->name;

		apk_print_indented(&indent, APK_BLOB_STR(name->name));
		match++;
	}
151
	apk_print_indented_end(&indent);
152
153
154
155
156
157
158
159
160
161
162
163
164
	return match;
}

static int cmp_remove(struct apk_change *change)
{
	return change->new_pkg == NULL;
}

static int cmp_new(struct apk_change *change)
{
	return change->old_pkg == NULL;
}

165
166
167
168
169
static int cmp_reinstall(struct apk_change *change)
{
	return change->reinstall;
}

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
static int cmp_downgrade(struct apk_change *change)
{
	if (change->new_pkg == NULL || change->old_pkg == NULL)
		return 0;
	if (apk_pkg_version_compare(change->new_pkg, change->old_pkg)
	    & APK_VERSION_LESS)
		return 1;
	return 0;
}

static int cmp_upgrade(struct apk_change *change)
{
	if (change->new_pkg == NULL || change->old_pkg == 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->new_pkg, change->old_pkg) &
	     (APK_VERSION_GREATER | APK_VERSION_EQUAL)) &&
	    (change->new_pkg != change->old_pkg))
		return 1;

	return 0;
}

static void run_triggers(struct apk_database *db, struct apk_changeset *changeset)
{
199
200
	struct apk_change *change;
	struct apk_installed_package *ipkg;
201
202
203
204

	if (apk_db_fire_triggers(db) == 0)
		return;

205
206
	foreach_array_item(change, changeset->changes) {
		struct apk_package *pkg = change->new_pkg;
207
208
209
		if (pkg == NULL)
			continue;
		ipkg = pkg->ipkg;
Natanael Copa's avatar
Natanael Copa committed
210
		if (ipkg == NULL || ipkg->pending_triggers->num == 0)
211
212
213
214
215
216
217
218
219
			continue;

		*apk_string_array_add(&ipkg->pending_triggers) = NULL;
		apk_ipkg_run_script(ipkg, db, APK_SCRIPT_TRIGGER,
				    ipkg->pending_triggers->item);
		apk_string_array_free(&ipkg->pending_triggers);
	}
}

220
221
222
223
224
225
226
227
228
229
230
231
232
#define PRE_COMMIT_HOOK		0
#define POST_COMMIT_HOOK	1

struct apk_commit_hook {
	struct apk_database *db;
	int type;
};

static int run_commit_hook(void *ctx, int dirfd, const char *file)
{
	static char *const commit_hook_str[] = { "pre-commit", "post-commit" };
	struct apk_commit_hook *hook = (struct apk_commit_hook *) ctx;
	struct apk_database *db = hook->db;
233
	struct apk_out *out = &db->ctx->out;
234
235
	char fn[PATH_MAX], *argv[] = { fn, (char *) commit_hook_str[hook->type], NULL };

236
	if (file[0] == '.') return 0;
237
	if ((db->ctx->flags & (APK_NO_SCRIPTS | APK_SIMULATE)) != 0) return 0;
238
239

	snprintf(fn, sizeof(fn), "etc/apk/commit_hooks.d" "/%s", file);
240
241
	if ((db->ctx->flags & APK_NO_COMMIT_HOOKS) != 0) {
		apk_msg(out, "Skipping: %s %s", fn, commit_hook_str[hook->type]);
Henrik Riomar's avatar
Henrik Riomar committed
242
243
		return 0;
	}
244
	apk_dbg(out, "Executing: %s %s", fn, commit_hook_str[hook->type]);
245
246

	if (apk_db_run_script(db, fn, argv) < 0 && hook->type == PRE_COMMIT_HOOK)
247
		return -2;
248
249
250
251
252
253
254
255
256
257
258

	return 0;
}

static int run_commit_hooks(struct apk_database *db, int type)
{
	struct apk_commit_hook hook = { .db = db, .type = type };
	return apk_dir_foreach_file(openat(db->root_fd, "etc/apk/commit_hooks.d", O_RDONLY | O_CLOEXEC),
				    run_commit_hook, &hook);
}

259
260
261
262
int apk_solver_commit_changeset(struct apk_database *db,
				struct apk_changeset *changeset,
				struct apk_dependency_array *world)
{
263
264
	struct apk_out *out = &db->ctx->out;
	struct progress prog = { .prog = db->ctx->progress };
265
	struct apk_change *change;
266
267
	char buf[32];
	const char *size_unit;
268
	off_t humanized, size_diff = 0, download_size = 0;
269
	int r, errors = 0;
270

271
	assert(world);
272
	if (apk_db_check_world(db, world) != 0) {
273
274
		apk_err(out, "Not committing changes due to missing repository tags. "
			"Use --force-broken-world to override.");
275
276
277
278
279
280
281
		return -1;
	}

	if (changeset->changes == NULL)
		goto all_done;

	/* Count what needs to be done */
282
	foreach_array_item(change, changeset->changes) {
283
		count_change(change, &prog.total);
284
		if (change->new_pkg) {
285
			size_diff += change->new_pkg->installed_size;
286
287
288
289
			if (change->new_pkg != change->old_pkg &&
			    !(change->new_pkg->repos & db->local_repos))
				download_size += change->new_pkg->size;
		}
290
		if (change->old_pkg)
291
			size_diff -= change->old_pkg->installed_size;
292
293
	}

294
295
296
	if ((apk_out_verbosity(out) > 1 || (db->ctx->flags & APK_INTERACTIVE)) &&
	    !(db->ctx->flags & APK_SIMULATE)) {
		r = dump_packages(out, changeset, cmp_remove,
297
				  "The following packages will be REMOVED");
298
		r += dump_packages(out, changeset, cmp_downgrade,
299
				   "The following packages will be DOWNGRADED");
300
301
		if (r || (db->ctx->flags & APK_INTERACTIVE) || apk_out_verbosity(out) > 2) {
			r += dump_packages(out, changeset, cmp_new,
302
					   "The following NEW packages will be installed");
303
			r += dump_packages(out, changeset, cmp_upgrade,
304
					   "The following packages will be upgraded");
305
			r += dump_packages(out, changeset, cmp_reinstall,
306
					   "The following packages will be reinstalled");
307
308
			if (download_size) {
				size_unit = apk_get_human_size(download_size, &humanized);
309
				apk_msg(out, "Need to download %lld %s of packages.",
310
311
312
					(long long)humanized, size_unit);
			}
			size_unit = apk_get_human_size(llabs(size_diff), &humanized);
313
			apk_msg(out, "After this operation, %lld %s of %s.",
314
				(long long)humanized,
Timo Teräs's avatar
Timo Teräs committed
315
				size_unit,
316
				(size_diff < 0) ?
Timo Teräs's avatar
Timo Teräs committed
317
318
				"disk space will be freed" :
				"additional disk space will be used");
319
		}
320
		if (r > 0 && (db->ctx->flags & APK_INTERACTIVE)) {
321
322
323
324
325
326
327
328
			printf("Do you want to continue [Y/n]? ");
			fflush(stdout);
			r = fgetc(stdin);
			if (r != 'y' && r != 'Y' && r != '\n')
				return -1;
		}
	}

329
	if (run_commit_hooks(db, PRE_COMMIT_HOOK) == -2)
330
331
		return -1;

332
	/* Go through changes */
333
	foreach_array_item(change, changeset->changes) {
334
335
336
		r = change->old_pkg &&
			(change->old_pkg->ipkg->broken_files ||
			 change->old_pkg->ipkg->broken_script);
337
338
339
340
		if (print_change(db, change, prog.done.changes, prog.total.changes)) {
			prog.pkg = change->new_pkg;
			progress_cb(&prog, 0);

341
			if (!(db->ctx->flags & APK_SIMULATE) &&
342
343
344
345
			    ((change->old_pkg != change->new_pkg) ||
			     (change->reinstall && pkg_available(db, change->new_pkg)))) {
				r = apk_db_install_pkg(db, change->old_pkg, change->new_pkg,
						       progress_cb, &prog) != 0;
346
			}
347
348
			if (r == 0 && change->new_pkg && change->new_pkg->ipkg)
				change->new_pkg->ipkg->repository_tag = change->new_repository_tag;
349
		}
350
		errors += r;
351
352
		count_change(change, &prog.done);
	}
353
	apk_print_progress(&prog.prog, prog.total.bytes + prog.total.packages,
354
			   prog.total.bytes + prog.total.packages);
355

356
	apk_db_update_directory_permissions(db);
357
358
359
360
	run_triggers(db, changeset);

all_done:
	apk_dependency_array_copy(&db->world, world);
361
	if (apk_db_write_config(db) != 0) errors++;
362
	run_commit_hooks(db, POST_COMMIT_HOOK);
363

364
	if (!db->performing_self_upgrade) {
365
		if (errors)
366
367
			snprintf(buf, sizeof(buf), "%d error%s;", errors,
				 errors > 1 ? "s" : "");
368
369
		else
			strcpy(buf, "OK:");
370
371
372
373
374
375
376
		if (apk_out_verbosity(out) > 1) {
			apk_msg(out, "%s %d packages, %d dirs, %d files, %zu MiB",
				buf,
				db->installed.stats.packages,
				db->installed.stats.dirs,
				db->installed.stats.files,
				db->installed.stats.bytes / (1024 * 1024));
377
		} else {
378
379
380
381
			apk_msg(out, "%s %zu MiB in %d packages",
				buf,
				db->installed.stats.bytes / (1024 * 1024),
				db->installed.stats.packages);
382
383
		}
	}
384
	return errors;
385
386
}

387
enum {
388
389
390
	STATE_PRESENT		= 0x80000000,
	STATE_MISSING		= 0x40000000,
	STATE_COUNT_MASK	= 0x0000ffff,
391
};
392

393
394
395
396
397
398
399
400
401
struct print_state {
	struct apk_database *db;
	struct apk_dependency_array *world;
	struct apk_indent i;
	struct apk_name_array *missing;
	const char *label;
	int num_labels;
	int match;
};
402

403
404
405
static void label_start(struct print_state *ps, const char *text)
{
	if (ps->label) {
406
		apk_print_indented_line(&ps->i, "  %s:\n", ps->label);
407
408
409
		ps->label = NULL;
		ps->num_labels++;
	}
410
	if (!ps->i.x) apk_print_indented_group(&ps->i, 0, "    %s", text);
411
412
413
}
static void label_end(struct print_state *ps)
{
414
	apk_print_indented_end(&ps->i);
415
416
}

417
static void print_pinning_errors(struct print_state *ps, struct apk_package *pkg, unsigned int tag)
418
{
419
	struct apk_database *db = ps->db;
420
421
422
423
424
	int i;

	if (pkg->ipkg != NULL)
		return;

425
426
427
	if (!(pkg->repos & db->available_repos)) {
		label_start(ps, "masked in:");
		apk_print_indented_fmt(&ps->i, "--no-network");
428
	} else if (pkg->repos == BIT(APK_REPOSITORY_CACHED) && !pkg->filename) {
429
430
		label_start(ps, "masked in:");
		apk_print_indented_fmt(&ps->i, "cache");
431
432
433
434
435
436
437
438
	} else {
		if (pkg->repos & apk_db_get_pinning_mask_repos(db, APK_DEFAULT_PINNING_MASK | BIT(tag)))
			return;
		for (i = 0; i < db->num_repo_tags; i++) {
			if (pkg->repos & db->repo_tags[i].allowed_repos) {
				label_start(ps, "masked in:");
				apk_print_indented(&ps->i, db->repo_tags[i].tag);
			}
439
		}
440
	}
441
	label_end(ps);
442
443
}

444
static void print_conflicts(struct print_state *ps, struct apk_package *pkg)
445
{
446
447
	struct apk_provider *p;
	struct apk_dependency *d;
448
	char tmp[256];
449
	int once;
450

451
	foreach_array_item(p, pkg->name->providers) {
452
		if (p->pkg == pkg || !p->pkg->marked)
453
			continue;
454
455
456
457
		label_start(ps, "conflicts:");
		apk_print_indented_fmt(&ps->i, PKG_VER_FMT, PKG_VER_PRINTF(p->pkg));
	}
	foreach_array_item(d, pkg->provides) {
458
		once = 1;
459
		foreach_array_item(p, d->name->providers) {
460
461
			if (!p->pkg->marked)
				continue;
462
463
			if (d->version == &apk_atom_null &&
			    p->version == &apk_atom_null)
464
				continue;
465
466
			if (once && p->pkg == pkg &&
			    p->version == d->version) {
467
468
469
				once = 0;
				continue;
			}
470
471
			label_start(ps, "conflicts:");
			apk_print_indented_fmt(
472
				&ps->i, PKG_VER_FMT "[%s]",
473
				PKG_VER_PRINTF(p->pkg),
474
				apk_dep_snprintf(tmp, sizeof(tmp), d));
475
476
477
478
		}
	}
	label_end(ps);
}
479

480
static void print_dep(struct apk_package *pkg0, struct apk_dependency *d0, struct apk_package *pkg, void *ctx)
481
482
{
	struct print_state *ps = (struct print_state *) ctx;
483
	const char *label = (ps->match & APK_DEP_SATISFIES) ? "satisfies:" : "breaks:";
484
	char tmp[256];
485

486
487
488
489
490
491
492
493
494
495
496
497
	label_start(ps, label);
	if (pkg0 == NULL)
		apk_print_indented_fmt(&ps->i, "world[%s]", apk_dep_snprintf(tmp, sizeof(tmp), d0));
	else
		apk_print_indented_fmt(&ps->i, PKG_VER_FMT "[%s]",
				       PKG_VER_PRINTF(pkg0),
				       apk_dep_snprintf(tmp, sizeof(tmp), d0));
}

static void print_deps(struct print_state *ps, struct apk_package *pkg, int match)
{
	ps->match = match;
498
499
500
	match |= APK_FOREACH_MARKED | APK_FOREACH_DEP;
	apk_pkg_foreach_matching_dependency(NULL, ps->world, match|apk_foreach_genid(), pkg, print_dep, ps);
	apk_pkg_foreach_reverse_dependency(pkg, match|apk_foreach_genid(), print_dep, ps);
501
	label_end(ps);
502
503
}

504
static void analyze_package(struct print_state *ps, struct apk_package *pkg, unsigned int tag)
505
{
506
	char pkgtext[256];
507

508
509
	snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(pkg));
	ps->label = pkgtext;
510

511
512
	print_pinning_errors(ps, pkg, tag);
	print_conflicts(ps, pkg);
513
	print_deps(ps, pkg, APK_DEP_CONFLICTS);
514
	if (ps->label == NULL)
515
		print_deps(ps, pkg, APK_DEP_SATISFIES);
516
517
518
519
520
521
522
523
}

static void analyze_name(struct print_state *ps, struct apk_name *name)
{
	struct apk_name **pname0, *name0;
	struct apk_provider *p0;
	struct apk_dependency *d0;
	char tmp[256];
524
	unsigned int genid;
525
	int refs;
526
527
528
529
530
531

	if (name->providers->num) {
		snprintf(tmp, sizeof(tmp), "%s (virtual)", name->name);
		ps->label = tmp;

		label_start(ps, "provided by:");
532
533
		foreach_array_item(p0, name->providers)
			p0->pkg->name->state_int++;
534
		foreach_array_item(p0, name->providers) {
535
536
537
538
539
540
541
542
543
544
545
			name0 = p0->pkg->name;
			refs = (name0->state_int & STATE_COUNT_MASK);
			if (refs == name0->providers->num) {
				/* name only */
				apk_print_indented(&ps->i, APK_BLOB_STR(name0->name));
				name0->state_int &= ~STATE_COUNT_MASK;
			} else if (refs > 0) {
				/* individual package */
				apk_print_indented_fmt(&ps->i, PKG_VER_FMT, PKG_VER_PRINTF(p0->pkg));
				name0->state_int--;
			}
546
547
548
		}
		label_end(ps);
	} else {
549
		snprintf(tmp, sizeof(tmp), "%s (no such package)", name->name);
550
551
		ps->label = tmp;
	}
552

553
554
555
	label_start(ps, "required by:");
	foreach_array_item(d0, ps->world) {
		if (d0->name != name || d0->conflict)
556
			continue;
557
558
559
		apk_print_indented_fmt(&ps->i, "world[%s]",
			apk_dep_snprintf(tmp, sizeof(tmp), d0));
	}
560
	genid = apk_foreach_genid();
561
562
563
	foreach_array_item(pname0, name->rdepends) {
		name0 = *pname0;
		foreach_array_item(p0, name0->providers) {
564
			if (!p0->pkg->marked)
565
				continue;
566
567
568
			if (p0->pkg->foreach_genid == genid)
				continue;
			p0->pkg->foreach_genid = genid;
569
570
571
572
573
574
575
576
577
578
579
			foreach_array_item(d0, p0->pkg->depends) {
				if (d0->name != name || d0->conflict)
					continue;
				apk_print_indented_fmt(&ps->i,
					PKG_VER_FMT "[%s]",
					PKG_VER_PRINTF(p0->pkg),
					apk_dep_snprintf(tmp, sizeof(tmp), d0));
				break;
			}
			if (d0 != NULL)
				break;
580
		}
581
582
583
	}
	label_end(ps);
}
584

585
586
587
static void analyze_deps(struct print_state *ps, struct apk_dependency_array *deps)
{
	struct apk_dependency *d0;
588
	struct apk_name *name0;
589
590

	foreach_array_item(d0, deps) {
591
		name0 = d0->name;
592
593
		if (d0->conflict)
			continue;
594
		if ((name0->state_int & (STATE_PRESENT | STATE_MISSING)) != 0)
595
			continue;
596
597
		name0->state_int |= STATE_MISSING;
		analyze_name(ps, name0);
598
599
600
601
602
603
604
	}
}

void apk_solver_print_errors(struct apk_database *db,
			     struct apk_changeset *changeset,
			     struct apk_dependency_array *world)
{
605
	struct apk_out *out = &db->ctx->out;
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
	struct print_state ps;
	struct apk_change *change;
	struct apk_dependency *p;

	/* ERROR: unsatisfiable dependencies:
	 *   name:
	 *     required by: a b c d e
	 *     not available in any repository
	 *   name (virtual):
	 *     required by: a b c d e
	 *     provided by: foo bar zed
	 *   pkg-1.2:
	 *     masked by: @testing
	 *     satisfies: a[pkg]
	 *     conflicts: pkg-2.0 foo-1.2 bar-1.2
	 *     breaks: b[pkg>2] c[foo>2] d[!pkg]
	 *
	 * When two packages provide same name 'foo':
	 *   a-1:
	 *     satisfies: world[a]
	 *     conflicts: b-1[foo]
	 *   b-1:
	 *     satisfies: world[b]
	 *     conflicts: a-1[foo]
	 * 
	 *   c-1:
	 *     satisfies: world[a]
	 *     conflicts: c-1[foo]  (self-conflict by providing foo twice)
	 *
	 * When two packages get pulled in:
	 *   a-1:
	 *     satisfies: app1[so:a.so.1]
	 *     conflicts: a-2
	 *   a-2:
	 *     satisfies: app2[so:a.so.2]
	 *     conflicts: a-1
	 *
	 * satisfies lists all dependencies that is not satisfiable by
	 * any other selected version. or all of them with -v.
645
	 */
646
647
648
649
 
	/* Construct information about names */
	foreach_array_item(change, changeset->changes) {
		struct apk_package *pkg = change->new_pkg;
650
651
		if (pkg == NULL)
			continue;
652
		pkg->marked = 1;
653
		pkg->name->state_int |= STATE_PRESENT;
654
		foreach_array_item(p, pkg->provides)
655
			p->name->state_int |= STATE_PRESENT;
656
657
	}

658
659
660
661
662
	/* Analyze is package, and missing names referred to */
	ps = (struct print_state) {
		.db = db,
		.world = world,
	};
663
664
	apk_err(out, "unable to select packages:");
	apk_print_indented_init(&ps.i, out, 1);
665
666
	analyze_deps(&ps, world);
	foreach_array_item(change, changeset->changes) {
667
668
669
		struct apk_package *pkg = change->new_pkg;
		if (pkg == NULL)
			continue;
670
671
		analyze_package(&ps, pkg, change->new_repository_tag);
		analyze_deps(&ps, pkg->depends);
672
673
	}

674
675
	if (!ps.num_labels)
		apk_print_indented_line(&ps.i, "Huh? Error reporter did not find the broken constraints.\n");
676
677
678
679
680
681
}

int apk_solver_commit(struct apk_database *db,
		      unsigned short solver_flags,
		      struct apk_dependency_array *world)
{
682
	struct apk_out *out = &db->ctx->out;
683
684
685
686
	struct apk_changeset changeset = {};
	int r;

	if (apk_db_check_world(db, world) != 0) {
687
688
		apk_err(out, "Not committing changes due to missing repository tags. "
			"Use --force-broken-world to override.");
689
690
691
692
		return -1;
	}

	r = apk_solver_solve(db, solver_flags, world, &changeset);
693
	if (r == 0)
694
		r = apk_solver_commit_changeset(db, &changeset, world);
695
	else
696
697
		apk_solver_print_errors(db, &changeset, world);

698
	apk_change_array_free(&changeset.changes);
699
700
	return r;
}