Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
deletion: respect provides/requires
Baptiste Daroussin committed 3 years ago
commit 298301edb2916dffb3bc0d203186a5fc8d56f136
parent a0bdf00
4 files changed +198 -23
modified libpkg/pkg_jobs.c
@@ -1,10 +1,9 @@
/*-
-
 * Copyright (c) 2011-2016 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2013-2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -66,6 +65,8 @@
#include "private/pkg_jobs.h"
#include "tllist.h"

+
typedef tll(struct pkg *) pkg_chain_t;
+

extern struct pkg_ctx ctx;

static int pkg_jobs_installed_local_pkg(struct pkg_jobs *j, struct pkg *pkg);
@@ -511,6 +512,23 @@ pkg_jobs_process_add_request(struct pkg_jobs *j)
	tll_free(to_process);
}

+
static bool
+
append_to_del_request(struct pkg_jobs *j, pkg_chain_t *to_process, const char *uid, const char *reqname)
+
{
+
	struct pkg *p;
+

+
	p = pkg_jobs_universe_get_local(j->universe, uid, 0);
+
	if (p == NULL)
+
		return (true);
+
	if (p->locked) {
+
		pkg_emit_error("%s is locked cannot delete %s", p->name,
+
		   reqname);
+
		return (false);
+
	}
+
	tll_push_back(*to_process, p);
+
	return (true);
+
}
+

/*
 * For delete request we merely check rdeps and force flag
 */
@@ -522,8 +540,11 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
	struct pkg_dep *d = NULL;
	struct pkg *lp;
	int rc = EPKG_OK;
-
	tll(struct pkg *) to_process = tll_init();
+
	pkg_chain_t to_process = tll_init();
	pkghash_it it;
+
	struct pkg *npkg;
+
	struct pkgdb_it *lit, *rit;
+
	bool anotherone;

	if (force)
		return (EPKG_OK);
@@ -534,20 +555,100 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
	it = pkghash_iterator(j->request_delete);
	while (pkghash_next(&it)) {
		req = it.value;
+
		if (req->processed)
+
			continue;
+
		req->processed = true;
+
		lp = req->item->pkg;
		d = NULL;
-
		while (pkg_rdeps(req->item->pkg, &d) == EPKG_OK) {
-
			if (pkghash_get(j->request_delete, d->uid))
+
		while (pkg_rdeps(lp, &d) == EPKG_OK) {
+
			if (!append_to_del_request(j, &to_process, d->uid,
+
			    lp->name))
+
				rc = EPKG_FATAL;
+
		}
+

+
		tll_foreach(lp->provides, i) {
+
			/*
+
			 * if something else to provide the same thing we can
+
			 * safely delete
+
			 */
+
			lit = pkgdb_query_provide(j->db, i->item);
+
			if (lit == NULL)
+
				continue;
+
			npkg = NULL;
+
			anotherone = false;
+
			while (pkgdb_it_next(lit, &npkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
				/* skip myself */
+
				if (strcmp(npkg->uid, lp->uid) == 0)
+
					continue;
+
				req = pkghash_get_value(j->request_delete, lp->uid);
+
				/*
+
				 * skip already processed provides
+
				 * if 3 packages providing the same "provide"
+
				 * are in the request delete they needs to be
+
				 * counted as to be removed and then if no
+
				 * packages are left providing the provide are
+
				 * left after the removal of those packages
+
				 * cascade.
+
				 */
+
				if (req != NULL && req->processed)
+
					continue;
+
				anotherone = true;
+
				break;
+
			}
+
			if (anotherone)
+
				continue;
+
			rit = pkgdb_query_require(j->db, i->item);
+
			if (rit == NULL)
				continue;

-
			lp = pkg_jobs_universe_get_local(j->universe, d->uid, 0);
-
			if (lp) {
-
				if (lp->locked) {
-
					pkg_emit_error("%s is locked, "
-
					    "cannot delete %s", lp->name,
-
					   req->item->pkg->name);
+
			npkg = NULL;
+
			while (pkgdb_it_next(rit, &npkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
				if (!append_to_del_request(j, &to_process,
+
				    npkg->uid, lp->name))
+
					rc = EPKG_FATAL;
+
			}
+
		}
+

+
		tll_foreach(lp->shlibs_provided, i) {
+
			/*
+
			 * if something else to provide the same thing we can
+
			 * safely delete
+
			 */
+
			lit = pkgdb_query_shlib_provide(j->db, i->item);
+
			if (lit == NULL)
+
				continue;
+
			npkg = NULL;
+
			anotherone = false;
+
			while (pkgdb_it_next(lit, &npkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
				/* skip myself */
+
				if (strcmp(npkg->uid, lp->uid) == 0)
+
					continue;
+
				req = pkghash_get_value(j->request_delete, lp->uid);
+
				/*
+
				 * skip already processed provides
+
				 * if 3 packages providing the same "provide"
+
				 * are in the request delete they needs to be
+
				 * counted as to be removed and then if no
+
				 * packages are left providing the provide are
+
				 * left after the removal of those packages
+
				 * cascade.
+
				 */
+
				if (req != NULL && req->processed)
+
					continue;
+
				anotherone = true;
+
				break;
+
			}
+
			if (anotherone)
+
				continue;
+
			rit = pkgdb_query_shlib_require(j->db, i->item);
+
			if (rit == NULL)
+
				continue;
+

+
			npkg = NULL;
+
			while (pkgdb_it_next(rit, &npkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
				if (!append_to_del_request(j, &to_process,
+
				    npkg->uid, lp->name))
					rc = EPKG_FATAL;
-
				}
-
				tll_push_back(to_process, lp);
			}
		}
	}
@@ -562,6 +663,7 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
			return (EPKG_FATAL);
		}
	}
+

	if (tll_length(to_process) > 0)
		rc = pkg_jobs_process_delete_request(j);
	tll_free(to_process);
@@ -1470,8 +1572,9 @@ jobs_solve_deinstall(struct pkg_jobs *j)
			pkg_emit_notice("No packages matched for pattern '%s'\n", jp->pattern);
		}

-
		while (pkgdb_it_next(it, &pkg,
-
				PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS) == EPKG_OK) {
+
		while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS|
+
		    PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS|PKG_LOAD_PROVIDES|
+
		    PKG_LOAD_SHLIBS_PROVIDED) == EPKG_OK) {
			if(pkg->locked) {
				if (tsearch(pkg, &j->lockedpkgs, comp) == NULL) {
					return (EPKG_FATAL);
modified libpkg/pkg_jobs_universe.c
@@ -58,13 +58,10 @@ pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe,
	struct pkg_job_universe_item *unit, *cur, *found;

	if (flag == 0) {
-
		if (!IS_DELETE(universe->j))
-
			flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS|
-
				PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
-
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_ANNOTATIONS|
-
				PKG_LOAD_CONFLICTS;
-
		else
-
			flag = PKG_LOAD_BASIC|PKG_LOAD_RDEPS|PKG_LOAD_DEPS|PKG_LOAD_ANNOTATIONS;
+
		flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS|
+
			PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
+
			PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_ANNOTATIONS|
+
			PKG_LOAD_CONFLICTS;
	}

	unit = pkghash_get_value(universe->items, uid);
modified libpkg/private/pkg_jobs.h
@@ -56,6 +56,7 @@ struct pkg_job_request_item {
struct pkg_job_request {
	struct pkg_job_request_item *item;
	bool skip;
+
	bool processed;
	bool automatic;
};

modified tests/frontend/requires.sh
@@ -3,7 +3,8 @@
. $(atf_get_srcdir)/test_environment.sh

tests_init \
-
	requires
+
	requires \
+
	requires_del

requires_body() {
	mkdir reposconf
@@ -68,3 +69,76 @@ Number of packages to be installed: 2
		-s exit:0 \
		pkg autoremove -n
}
+

+
requires_del_body() {
+
	mkdir reposconf
+
	cat << EOF >> reposconf/repo.conf
+
local1: {
+
	url: file://${TMPDIR},
+
	enabled: true
+
}
+
EOF
+

+
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg a a 1.0
+
	cat << EOF >> a.ucl
+
provides: [a-1]
+
EOF
+

+
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg b b 1.0
+
	cat << EOF >> b.ucl
+
requires: [a-1]
+
EOF
+

+
	for p in a b; do
+
		atf_check \
+
		    -o ignore \
+
		    -e empty \
+
		    -s exit:0 \
+
		    pkg create -M ./${p}.ucl
+
	done
+

+
	atf_check \
+
	    -o ignore \
+
	    -e empty \
+
	    -s exit:0 \
+
	    pkg repo .
+

+
	OUTPUT="Updating local1 repository catalogue...
+
${JAILED}Fetching meta.conf:  done
+
${JAILED}Fetching packagesite.pkg:  done
+
Processing entries:  done
+
local1 repository update completed. 2 packages processed.
+
All repositories are up to date.
+
Checking integrity... done (0 conflicting)
+
The following 2 package(s) will be affected (of 0 checked):
+

+
New packages to be INSTALLED:
+
	a: 1.0
+
	b: 1.0
+

+
Number of packages to be installed: 2
+
"
+
	atf_check \
+
	    -o inline:"${OUTPUT}" \
+
	    -s exit:1 \
+
	    pkg -o REPOS_DIR="${TMPDIR}/reposconf" install -n b
+

+
	atf_check \
+
	    -o ignore \
+
	    -s exit:0 \
+
	    pkg -o REPOS_DIR="${TMPDIR}/reposconf" install -y b
+

+
	OUTPUT2="Checking integrity... done (0 conflicting)
+
Deinstallation has been requested for the following 2 packages (of 0 packages in the universe):
+

+
Installed packages to be REMOVED:
+
	a: 1.0
+
	b: 1.0
+

+
Number of packages to be removed: 2
+
"
+
	atf_check \
+
		-o inline:"${OUTPUT2}" \
+
		-s exit:0 \
+
		pkg delete -n a
+
}