Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
libpkg: Try to merge config files across split upgrades
Mark Johnston committed 3 years ago
commit 4ddb2348f6e1386395c2f1aab39c68d9efa565e5
parent 8b18fd8
5 files changed +75 -28
modified libpkg/pkg_add.c
@@ -1191,9 +1191,6 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,

	assert(path != NULL);

-
	if (local != NULL)
-
		flags |= PKG_ADD_UPGRADE;
-

	/*
	 * Open the package archive file, read all the meta files and set the
	 * current archive_entry to the first non-meta file.
@@ -1208,7 +1205,8 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
	}
	if ((flags & PKG_ADD_SPLITTED_UPGRADE) == 0)
		pkg_emit_new_action();
-
	if ((flags & PKG_ADD_UPGRADE) == 0 || local == NULL)
+
	if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
+
	    PKG_ADD_UPGRADE)
		pkg_emit_install_begin(pkg);
	else
		pkg_emit_upgrade_begin(pkg, local);
@@ -1305,7 +1303,11 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
		}
	}

-
	if (local != NULL) {
+
	/*
+
	 * If this was a split upgrade, the old package has been entirely
+
	 * removed already.
+
	 */
+
	if (local != NULL && (flags & PKG_ADD_SPLITTED_UPGRADE) == 0) {
		pkg_open_root_fd(local);
		pkg_debug(1, "Cleaning up old version");
		if (pkg_add_cleanup_old(db, local, pkg, t, flags) != EPKG_OK) {
@@ -1339,14 +1341,11 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,

	pkg_start_stop_rc_scripts(pkg, PKG_RC_START);

-
	if ((flags & PKG_ADD_UPGRADE) == 0)
+
	if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
+
	    PKG_ADD_UPGRADE)
		pkg_emit_install_finished(pkg, local);
-
	else {
-
		if (local != NULL)
-
			pkg_emit_upgrade_finished(pkg, local);
-
		else
-
			pkg_emit_install_finished(pkg, local);
-
	}
+
	else
+
		pkg_emit_upgrade_finished(pkg, local);

	tll_foreach(pkg->message, m) {
		msg = m->item;
modified libpkg/pkg_delete.c
@@ -54,7 +54,8 @@
#endif

int
-
pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags, struct triggers *t)
+
pkg_delete(struct pkg *pkg, struct pkg *rpkg, struct pkgdb *db, int flags,
+
    struct triggers *t)
{
	xstring		*message = NULL;
	int		 ret;
@@ -67,11 +68,11 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags, struct triggers *t

	if (pkgdb_ensure_loaded(db, pkg, load_flags) != EPKG_OK)
		return (EPKG_FATAL);
+
	if (rpkg != NULL && pkgdb_ensure_loaded(db, rpkg, load_flags) != EPKG_OK)
+
		return (EPKG_FATAL);

-
	if ((flags & PKG_DELETE_UPGRADE) == 0) {
-
		pkg_emit_new_action();
-
		pkg_emit_deinstall_begin(pkg);
-
	}
+
	pkg_emit_new_action();
+
	pkg_emit_deinstall_begin(pkg);

	/* If the package is locked */
	if (pkg->locked) {
@@ -97,7 +98,7 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags, struct triggers *t
			return (ret);
	}

-
	if ((ret = pkg_delete_files(pkg, t)) != EPKG_OK)
+
	if ((ret = pkg_delete_files(pkg, rpkg, flags, t)) != EPKG_OK)
		return (ret);

	if ((flags & (PKG_DELETE_NOSCRIPT | PKG_DELETE_UPGRADE)) == 0) {
@@ -126,7 +127,6 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags, struct triggers *t
			pkg_emit_message(message->buf);
			xstring_free(message);
		}
-

	}

	return (pkgdb_unregister_pkg(db, pkg->id));
@@ -318,15 +318,37 @@ pkg_delete_file(struct pkg *pkg, struct pkg_file *file)
		pkg_add_dir_to_del(pkg, path, NULL);
}

+
/*
+
 * Handle a special case: the package is to be upgraded but is being deleted
+
 * temporarily to handle a file path conflict.  In this situation we shouldn't
+
 * remove configuration files.  For now, keep them if the replacement package
+
 * contains a configuration file at the same path.
+
 *
+
 * Note, this currently doesn't handle the case where a configuration file
+
 * participates in the conflict, i.e., it moves from one package to another.
+
 */
+
static bool
+
pkg_delete_skip_config(struct pkg *pkg, struct pkg *rpkg, struct pkg_file *file,
+
    int flags)
+
{
+
	if ((flags & PKG_DELETE_UPGRADE) == 0)
+
		return (false);
+
	if (pkghash_get(pkg->config_files_hash, file->path) == NULL)
+
		return (false);
+
	if (pkghash_get(rpkg->config_files_hash, file->path) == NULL)
+
		return (false);
+
	return (true);
+
}
+

int
-
pkg_delete_files(struct pkg *pkg, struct triggers *t)
+
pkg_delete_files(struct pkg *pkg, struct pkg *rpkg, int flags,
+
    struct triggers *t)
{
	struct pkg_file	*file = NULL;

	int		nfiles, cur_file = 0;

	nfiles = pkghash_count(pkg->filehash);
-

	if (nfiles == 0)
		return (EPKG_OK);

@@ -334,6 +356,8 @@ pkg_delete_files(struct pkg *pkg, struct triggers *t)
	pkg_emit_progress_start(NULL);

	while (pkg_files(pkg, &file) == EPKG_OK) {
+
		if (pkg_delete_skip_config(pkg, rpkg, file, flags))
+
			continue;
		append_touched_file(file->path);
		pkg_emit_progress_tick(cur_file++, nfiles);
		trigger_is_it_a_cleanup(t, file->path);
modified libpkg/pkg_jobs.c
@@ -582,8 +582,10 @@ pkg_jobs_set_execute_priority(struct pkg_jobs *j, struct pkg_solved *solved)
			ts = xcalloc(1, sizeof(struct pkg_solved));
			ts->type = PKG_SOLVED_UPGRADE_REMOVE;
			ts->items[0] = solved->items[1];
+
			ts->xlink = solved;
			solved->items[1] = NULL;
			solved->type = PKG_SOLVED_UPGRADE_INSTALL;
+
			solved->xlink = ts;
			tll_push_back(j->jobs, ts);
			j->count++;
			pkg_debug(2, "split upgrade request for %s",
@@ -2045,8 +2047,17 @@ pkg_jobs_handle_install(struct pkg_solved *ps, struct pkg_jobs *j,
	int flags = 0;
	int retcode = EPKG_FATAL;

-
	old = ps->items[1] ? ps->items[1]->pkg : NULL;
+
	/*
+
	 * For a split upgrade, pass along the old package even though it's
+
	 * already deleted, since we need it in order to merge configuration
+
	 * file changes.
+
	 */
	new = ps->items[0]->pkg;
+
	old = NULL;
+
	if (ps->items[1] != NULL)
+
		old = ps->items[1]->pkg;
+
	else if (ps->type == PKG_SOLVED_UPGRADE_INSTALL)
+
		old = ps->xlink->items[0]->pkg;

	req = pkghash_get_value(j->request_add, new->uid);
	if (req != NULL && req->item->jp != NULL &&
@@ -2074,9 +2085,11 @@ pkg_jobs_handle_install(struct pkg_solved *ps, struct pkg_jobs *j,
		flags |= PKG_ADD_NOSCRIPT;
	if ((j->flags & PKG_FLAG_FORCE_MISSING) == PKG_FLAG_FORCE_MISSING)
		flags |= PKG_ADD_FORCE_MISSING;
-
	flags |= PKG_ADD_UPGRADE;
-
	if (ps->type == PKG_SOLVED_UPGRADE_INSTALL)
-
		flags |= PKG_ADD_SPLITTED_UPGRADE;
+
	if (ps->type != PKG_SOLVED_INSTALL) {
+
		flags |= PKG_ADD_UPGRADE;
+
		if (ps->type == PKG_SOLVED_UPGRADE_INSTALL)
+
			flags |= PKG_ADD_SPLITTED_UPGRADE;
+
	}
	if (new->automatic || (j->flags & PKG_FLAG_AUTOMATIC) == PKG_FLAG_AUTOMATIC)
		flags |= PKG_ADD_AUTOMATIC;

@@ -2091,12 +2104,19 @@ pkg_jobs_handle_install(struct pkg_solved *ps, struct pkg_jobs *j,
static int
pkg_jobs_handle_delete(struct pkg_solved *ps, struct pkg_jobs *j)
{
+
	struct pkg *rpkg;
	int flags;

+
	rpkg = NULL;
	flags = 0;
	if ((j->flags & PKG_FLAG_NOSCRIPT) != 0)
		flags |= PKG_DELETE_NOSCRIPT;
-
	return (pkg_delete(ps->items[0]->pkg, j->db, flags, &j->triggers));
+
	if (ps->type == PKG_SOLVED_UPGRADE_REMOVE) {
+
		flags |= PKG_DELETE_UPGRADE;
+
		rpkg = ps->xlink->items[0]->pkg;
+
	}
+
	return (pkg_delete(ps->items[0]->pkg, rpkg, j->db, flags,
+
	    &j->triggers));
}

static int
modified libpkg/private/pkg.h
@@ -610,10 +610,12 @@ int pkg_get_myarch_legacy(char *pkgarch, size_t sz);
/**
 * Remove and unregister the package.
 * @param pkg An installed package to delete
+
 * @param rpkg A package which will replace pkg, or NULL
 * @param db An opened pkgdb
 * @return An error code.
 */
-
int pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags, struct triggers *);
+
int pkg_delete(struct pkg *pkg, struct pkg *rpkg, struct pkgdb *db, int flags,
+
    struct triggers *);
#define PKG_DELETE_UPGRADE	(1 << 1)	/* delete as a split upgrade */
#define PKG_DELETE_NOSCRIPT	(1 << 2)	/* don't run delete scripts */

@@ -683,7 +685,8 @@ pkg_formats packing_format_from_string(const char *str);
const char* packing_format_to_string(pkg_formats format);
bool packing_is_valid_format(const char *str);

-
int pkg_delete_files(struct pkg *pkg, struct triggers *t);
+
int pkg_delete_files(struct pkg *pkg, struct pkg *rpkg, int flags,
+
    struct triggers *t);
int pkg_delete_dirs(struct pkgdb *db, struct pkg *pkg, struct pkg *p);

/* pkgdb commands */
modified libpkg/private/pkg_jobs.h
@@ -63,6 +63,7 @@ struct pkg_job_request {

struct pkg_solved {
	struct pkg_job_universe_item *items[2]; /* to-add/to-delete */
+
	struct pkg_solved *xlink;	/* link split jobs together */
	pkg_solved_t type;
};
typedef tll(struct pkg_solved *) pkg_solved;