Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Rework messages to be fully context aware
Baptiste Daroussin committed 10 years ago
commit 9ec411c64ad7c5f8da7a5409e21d252ac46f6a32
parent 628d555e1119ca2fec06f627d225edb78244b65b
16 files changed +323 -103
modified libpkg/pkg.c
@@ -1751,74 +1751,75 @@ int
pkg_message_from_ucl(struct pkg *pkg, const ucl_object_t *obj)
{
	struct pkg_message *msg = NULL;
-
	const ucl_object_t *elt;
-

+
	const ucl_object_t *elt, *cur;
+
	ucl_object_iter_t it = NULL;

	if (ucl_object_type(obj) == UCL_STRING) {
-
		if (pkg->message == NULL) {
-
			msg = calloc(1, sizeof(*msg));
+
		msg = calloc(1, sizeof(*msg));

-
			if (msg == NULL) {
-
				pkg_emit_errno("malloc", "struct pkg_message");
-
				return (EPKG_FATAL);
-
			}
-
			msg->str = strdup(ucl_object_tostring(obj));
-
			msg->legacy = true;
-
		}
-
		else {
-
			/* Do no rewrite message with legacy message */
-
			return (EPKG_OK);
+
		if (msg == NULL) {
+
			pkg_emit_errno("malloc", "struct pkg_message");
+
			return (EPKG_FATAL);
		}
-

+
		msg->str = strdup(ucl_object_tostring(obj));
+
		msg->type = PKG_MESSAGE_ALWAYS;
+
		LL_APPEND(pkg->message, msg);
+
		return (EPKG_OK);
	}
-
	else {
-
		/* New format of pkg message */

-
		elt = ucl_object_find_key(obj, "message");
+
	/* New format of pkg message */
+
	if (ucl_object_type(obj) != UCL_ARRAY)
+
		pkg_emit_error("package message badly formatted, an array was"
+
		    " expected");
+

+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		elt = ucl_object_find_key(cur, "message");

		if (elt == NULL || ucl_object_type(elt) != UCL_STRING) {
-
			pkg_emit_error("package message lacks 'message' key that is required");
+
			pkg_emit_error("package message lacks 'message' key"
+
			    " that is required");

			return (EPKG_FATAL);
		}

-
		if (pkg->message != NULL) {
-
			if (pkg->message->legacy) {
-
				/* We can re-use legacy message */
-
				msg = pkg->message;
-
				msg->legacy = false;
-
				free(msg->str);
-
				msg->str = NULL;
-
			}
-
			else {
-
				pkg_emit_error("trying to rewrite message in a package");
-

-
				return (EPKG_FATAL);
-
			}
-
		}
-
		else {
-
			msg = calloc(1, sizeof(*msg));
+
		msg = calloc(1, sizeof(*msg));

-
			if (msg == NULL) {
-
				pkg_emit_errno("malloc", "struct pkg_message");
-
				return (EPKG_FATAL);
-
			}
+
		if (msg == NULL) {
+
			pkg_emit_errno("malloc", "struct pkg_message");
+
			return (EPKG_FATAL);
		}

		msg->str = strdup(ucl_object_tostring(elt));
-
		elt = ucl_object_find_key(obj, "minimum_version");
+
		msg->type = PKG_MESSAGE_ALWAYS;
+
		elt = ucl_object_find_key(cur, "type");
+
		if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
+
			if (strcasecmp(ucl_object_tostring(elt), "install") == 0)
+
				msg->type = PKG_MESSAGE_INSTALL;
+
			else if (strcasecmp(ucl_object_tostring(elt), "remove") == 0)
+
				msg->type = PKG_MESSAGE_REMOVE;
+
			else if (strcasecmp(ucl_object_tostring(elt), "upgrade") == 0)
+
				msg->type = PKG_MESSAGE_UPGRADE;
+
			else
+
				pkg_emit_error("Unknown message type,"
+
				    " message will always be printed");
+
		}
+
		if (msg->type != PKG_MESSAGE_UPGRADE) {
+
			LL_APPEND(pkg->message, msg);
+
			continue;
+
		}

+
		elt = ucl_object_find_key(cur, "minimum_version");
		if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
			msg->minimum_version = strdup(ucl_object_tostring(elt));
		}
-
		elt = ucl_object_find_key(obj, "maximum_version");

+
		elt = ucl_object_find_key(cur, "maximum_version");
		if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
			msg->maximum_version = strdup(ucl_object_tostring(elt));
		}
-
	}

-
	pkg->message = msg;
+
		LL_APPEND(pkg->message, msg);
+
	}

	return (EPKG_OK);
}
@@ -1856,27 +1857,52 @@ pkg_message_from_str(struct pkg *pkg, const char *str, size_t len)
ucl_object_t*
pkg_message_to_ucl(struct pkg *pkg)
{
+
	struct pkg_message *msg;
+
	ucl_object_t *array;
	ucl_object_t *obj;

-
	obj = ucl_object_typed_new (UCL_OBJECT);
-

-
	ucl_object_insert_key(obj,
-
			ucl_object_fromstring_common(pkg->message->str, 0,
-
					UCL_STRING_RAW|UCL_STRING_TRIM),
-
			"message", 0, false);
+
	array = ucl_object_typed_new(UCL_ARRAY);
+
	LL_FOREACH(pkg->message, msg) {
+
		obj = ucl_object_typed_new (UCL_OBJECT);

-
	if (pkg->message->maximum_version) {
-
		ucl_object_insert_key(obj,
-
				ucl_object_fromstring(pkg->message->maximum_version),
-
				"maximum_version", 0, false);
-
	}
-
	if (pkg->message->minimum_version) {
		ucl_object_insert_key(obj,
-
				ucl_object_fromstring(pkg->message->minimum_version),
-
				"minimum_version", 0, false);
+
		    ucl_object_fromstring_common(msg->str, 0,
+
		    UCL_STRING_RAW|UCL_STRING_TRIM),
+
		    "message", 0, false);
+

+
		switch (msg->type) {
+
		case PKG_MESSAGE_ALWAYS:
+
			break;
+
		case PKG_MESSAGE_INSTALL:
+
			ucl_object_insert_key(obj,
+
			    ucl_object_fromstring("install"),
+
			    "type", 0, false);
+
			break;
+
		case PKG_MESSAGE_UPGRADE:
+
			ucl_object_insert_key(obj,
+
			    ucl_object_fromstring("upgrade"),
+
			    "type", 0, false);
+
			break;
+
		case PKG_MESSAGE_REMOVE:
+
			ucl_object_insert_key(obj,
+
			    ucl_object_fromstring("remove"),
+
			    "type", 0, false);
+
			break;
+
		}
+
		if (msg->maximum_version) {
+
			ucl_object_insert_key(obj,
+
			    ucl_object_fromstring(msg->maximum_version),
+
			    "maximum_version", 0, false);
+
		}
+
		if (msg->minimum_version) {
+
			ucl_object_insert_key(obj,
+
			    ucl_object_fromstring(msg->minimum_version),
+
			    "minimum_version", 0, false);
+
		}
+
		ucl_array_append(array, obj);
	}

-
	return (obj);
+
	return (array);
}

char*
modified libpkg/pkg.h.in
@@ -1284,6 +1284,7 @@ typedef enum {
	PKG_EVENT_PLUGIN_INFO,
	PKG_EVENT_NOT_FOUND,
	PKG_EVENT_NEW_ACTION,
+
	PKG_EVENT_MESSAGE,
} pkg_event_t;

struct pkg_event {
@@ -1433,6 +1434,9 @@ struct pkg_event {
			int64_t current;
			int64_t total;
		} e_progress_tick;
+
		struct {
+
			const char *msg;
+
		} e_pkg_message;
	};
};

modified libpkg/pkg_add.c
@@ -383,7 +383,7 @@ pkg_globmatch(char *pattern, const char *name)
			path = g.gl_pathv[i];
			continue;
		}
-
		if (pkg_version_cmp(path, g.gl_pathv[i]) == '>')
+
		if (pkg_version_cmp(path, g.gl_pathv[i]) == 1)
			path = g.gl_pathv[i];
	}
	path = strdup(path);
@@ -565,15 +565,17 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
    struct pkg_manifest_key *keys, const char *reloc, struct pkg *remote,
    struct pkg *local)
{
-
	struct archive	*a;
-
	struct archive_entry *ae;
-
	struct pkg	*pkg = NULL;
-
	const char	*location;
-
	bool		 extract = true;
-
	bool		 handle_rc = false;
-
	int		 retcode = EPKG_OK;
-
	int		 ret;
-
	int nfiles;
+
	struct archive		*a;
+
	struct archive_entry	*ae;
+
	struct pkg		*pkg = NULL;
+
	struct sbuf		*message;
+
	struct pkg_message	*msg;
+
	const char		*location, *msgstr;
+
	bool			 extract = true;
+
	bool			 handle_rc = false;
+
	int			 retcode = EPKG_OK;
+
	int			 ret;
+
	int			 nfiles;

	assert(path != NULL);

@@ -717,6 +719,49 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
			else
				pkg_emit_install_finished(pkg, local);
		}
+

+
		if (pkg->message != NULL)
+
			message = sbuf_new_auto();
+
		LL_FOREACH(pkg->message, msg) {
+
			msgstr = NULL;
+
			if (msg->type == PKG_MESSAGE_ALWAYS) {
+
				msgstr = msg->str;
+
			} else if (local != NULL &&
+
			     msg->type == PKG_MESSAGE_UPGRADE) {
+
				if (msg->maximum_version == NULL &&
+
				    msg->minimum_version == NULL) {
+
					msgstr = msg->str;
+
				} else if (msg->maximum_version == NULL) {
+
					if (pkg_version_cmp(local->version, msg->minimum_version) == 1) {
+
						msgstr = msg->str;
+
					}
+
				} else if (msg->minimum_version == NULL) {
+
					if (pkg_version_cmp(local->version, msg->maximum_version) == -1) {
+
						msgstr = msg->str;
+
					}
+
				} else if (pkg_version_cmp(local->version, msg->maximum_version) == -1 &&
+
					    pkg_version_cmp(local->version, msg->minimum_version) == 1) {
+
					msgstr = msg->str;
+
				}
+
			} else if (local == NULL &&
+
			    msg->type == PKG_MESSAGE_INSTALL) {
+
				msgstr = msg->str;
+
			}
+
			if (msgstr != NULL) {
+
				if (sbuf_len(message) == 0) {
+
					pkg_sbuf_printf(message, "Message from "
+
					    "%n-%v:\n", pkg, pkg);
+
				}
+
				sbuf_printf(message, "%s\n", msgstr);
+
			}
+
		}
+
		if (pkg->message != NULL) {
+
			if (sbuf_len(message) > 0) {
+
				sbuf_finish(message);
+
				pkg_emit_message(sbuf_data(message));
+
			}
+
			sbuf_delete(message);
+
		}
	}

	cleanup:
modified libpkg/pkg_delete.c
@@ -56,6 +56,8 @@
int
pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags)
{
+
	struct pkg_message	*msg;
+
	struct sbuf	*message;
	int		 ret;
	bool		 handle_rc = false;
	const unsigned load_flags = PKG_LOAD_RDEPS|PKG_LOAD_FILES|PKG_LOAD_DIRS|
@@ -112,8 +114,28 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags)
	if (ret != EPKG_OK)
		return (ret);

-
	if ((flags & PKG_DELETE_UPGRADE) == 0)
+
	if ((flags & PKG_DELETE_UPGRADE) == 0) {
		pkg_emit_deinstall_finished(pkg);
+
		if (pkg->message != NULL)
+
			message = sbuf_new_auto();
+
		LL_FOREACH(pkg->message, msg) {
+
			if (msg->type == PKG_MESSAGE_REMOVE) {
+
				if (sbuf_len(message) == 0) {
+
					pkg_sbuf_printf(message, "Message from "
+
					    "%n-%v:\n", pkg, pkg);
+
				}
+
				sbuf_printf(message, "%s\n", msg->str);
+
			}
+
		}
+
		if (pkg->message != NULL) {
+
			if (sbuf_len(message) > 0) {
+
				sbuf_finish(message);
+
				pkg_emit_message(sbuf_data(message));
+
			}
+
			sbuf_delete(message);
+
		}
+

+
	}

	return (pkgdb_unregister_pkg(db, pkg->id));
}
modified libpkg/pkg_event.c
@@ -1014,3 +1014,13 @@ pkg_emit_new_action(void)

	pkg_emit_event(&ev);
}
+

+
void
+
pkg_emit_message(const char *message)
+
{
+
	struct pkg_event ev;
+

+
	ev.type = PKG_EVENT_MESSAGE;
+
	ev.e_pkg_message.msg = message;
+
	pkg_emit_event(&ev);
+
}
modified libpkg/pkg_manifest.c
@@ -141,11 +141,11 @@ static struct pkg_manifest_key {
	{ "maintainer",          offsetof(struct pkg, maintainer),
			TYPE_SHIFT(UCL_STRING), pkg_string},

-
	{ "message_new",             PKG_MESSAGE_NEW,
-
			TYPE_SHIFT(UCL_STRING)|TYPE_SHIFT(UCL_OBJECT), pkg_message},
+
	{ "messages",            PKG_MESSAGE_NEW,
+
			TYPE_SHIFT(UCL_STRING)|TYPE_SHIFT(UCL_ARRAY), pkg_message},

	{ "message",             PKG_MESSAGE_LEGACY,
-
			TYPE_SHIFT(UCL_STRING)|TYPE_SHIFT(UCL_OBJECT), pkg_message},
+
			TYPE_SHIFT(UCL_STRING)|TYPE_SHIFT(UCL_ARRAY), pkg_message},

	{ "name",                offsetof(struct pkg, name),
			TYPE_SHIFT(UCL_STRING)|TYPE_SHIFT(UCL_INT), pkg_string},
@@ -1229,11 +1229,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (pkg->message != NULL) {
		ucl_object_insert_key(top,
			pkg_message_to_ucl(pkg),
-
			"message_new", sizeof("message_new") - 1, false);
-
		ucl_object_insert_key(top,
-
			ucl_object_fromstring_common(pkg->message->str, 0,
-
					UCL_STRING_RAW|UCL_STRING_TRIM),
-
			"message", sizeof("message") - 1, false);
+
			"messages", sizeof("messages") - 1, false);
	}

	return (top);
modified libpkg/pkg_ports.c
@@ -1290,6 +1290,8 @@ pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
{
	const char *location;
	int rc = EPKG_OK;
+
	struct sbuf *message;
+
	struct pkg_message *msg;

	location = reloc;
	if (pkg_rootdir != NULL)
@@ -1317,8 +1319,24 @@ pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
		pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL);
	}

-
	if (rc == EPKG_OK)
+
	if (rc == EPKG_OK) {
		pkg_emit_install_finished(pkg, NULL);
+
		if (pkg->message != NULL)
+
			message = sbuf_new_auto();
+
		LL_FOREACH(pkg->message, msg) {
+
			if (msg->type == PKG_MESSAGE_ALWAYS ||
+
			    msg->type == PKG_MESSAGE_INSTALL) {
+
				sbuf_printf(message, "%s\n", msg->str);
+
			}
+
		}
+
		if (pkg->message != NULL) {
+
			if (sbuf_len(message) > 0) {
+
				sbuf_finish(message);
+
				pkg_emit_message(sbuf_data(message));
+
			}
+
			sbuf_delete(message);
+
		}
+
	}

cleanup:
	pkgdb_register_finale(db, rc);
modified libpkg/pkgdb_iterator.c
@@ -819,7 +819,7 @@ populate_pkg(sqlite3_stmt *stmt, struct pkg *pkg) {
				msg = sqlite3_column_text(stmt, icol);
				if (msg) {
					/* A stupid logic to detect legacy pkg message */
-
					if (msg[0] == '{') {
+
					if (msg[0] == '[') {
						pkg_message_from_str(pkg, msg, 0);
					}
					else {
modified libpkg/private/event.h
@@ -77,5 +77,6 @@ void pkg_emit_extract_finished(struct pkg *p);
void pkg_emit_delete_files_begin(struct pkg *p);
void pkg_emit_delete_files_finished(struct pkg *p);
void pkg_emit_new_action(void);
+
void pkg_emit_message(const char *msg);

#endif
modified libpkg/private/pkg.h
@@ -276,11 +276,19 @@ struct pkg_dep {
	bool		 locked;
};

+
typedef enum {
+
	PKG_MESSAGE_ALWAYS = 0,
+
	PKG_MESSAGE_INSTALL,
+
	PKG_MESSAGE_REMOVE,
+
	PKG_MESSAGE_UPGRADE,
+
} pkg_message_t;
+

struct pkg_message {
-
	char		*str;
-
	char		*minimum_version;
-
	char		*maximum_version;
-
	bool		legacy;
+
	char			*str;
+
	char			*minimum_version;
+
	char			*maximum_version;
+
	pkg_message_t		 type;
+
	struct pkg_message	*next;
};

enum pkg_conflict_type {
modified src/delete.c
@@ -222,6 +222,10 @@ exec_delete(int argc, char **argv)
	if (!rc || (retcode = pkg_jobs_apply(jobs)) != EPKG_OK)
		goto cleanup;

+
	if (messages != NULL) {
+
		sbuf_finish(messages);
+
		printf("%s", sbuf_data(messages));
+
	}
	pkgdb_compact(db);

	retcode = EX_OK;
modified src/event.c
@@ -627,15 +627,6 @@ event_callback(void *data, struct pkg_event *ev)
		if (quiet)
			break;
		pkg = ev->e_install_finished.pkg;
-
		if (pkg_has_message(pkg)) {
-

-
			if (pkg_need_message(pkg, ev->e_install_finished.old)) {
-
				if (messages == NULL)
-
					messages = sbuf_new_auto();
-
				pkg_sbuf_printf(messages, "Message for %n-%v:\n%M\n",
-
						pkg, pkg, pkg);
-
			}
-
		}
		break;
	case PKG_EVENT_EXTRACT_BEGIN:
		if (quiet)
@@ -737,15 +728,6 @@ event_callback(void *data, struct pkg_event *ev)
		if (quiet)
			break;
		pkg_new = ev->e_upgrade_finished.n;
-
		if (pkg_has_message(pkg_new)) {
-

-
			if (pkg_need_message(pkg_new, ev->e_upgrade_finished.o)) {
-
				if (messages == NULL)
-
					messages = sbuf_new_auto();
-
				pkg_sbuf_printf(messages, "Message for %n-%v:\n%M\n",
-
						pkg_new, pkg_new, pkg_new);
-
			}
-
		}
		break;
	case PKG_EVENT_LOCKED:
		pkg = ev->e_locked.pkg;
@@ -858,6 +840,11 @@ event_callback(void *data, struct pkg_event *ev)
	case PKG_EVENT_NEW_ACTION:
		nbdone++;
		break;
+
	case PKG_EVENT_MESSAGE:
+
		if (messages == NULL)
+
			messages = sbuf_new_auto();
+
		sbuf_cat(messages, ev->e_pkg_message.msg);
+
		break;
	default:
		break;
	}
modified src/register.c
@@ -331,8 +331,10 @@ exec_register(int argc, char **argv)

	retcode = pkg_add_port(db, pkg, input_path, location, testing_mode);

-
	if (!legacy && retcode == EPKG_OK && pkg_has_message(pkg))
-
		pkg_printf("%M\n", pkg);
+
	if (!legacy && retcode == EPKG_OK && messages != NULL) {
+
		sbuf_finish(messages);
+
		printf("%s\n", sbuf_data(messages));
+
	}

	pkg_free(pkg);

modified tests/Makefile.am
@@ -85,6 +85,7 @@ tests_scripts= \
		frontend/create.sh \
		frontend/delete.sh \
		frontend/lock.sh \
+
		frontend/messages.sh \
		frontend/packagesplit.sh \
		frontend/php-pr.sh \
		frontend/pubkey.sh \
modified tests/frontend/Kyuafile.in
@@ -11,6 +11,7 @@ atf_test_program{name='conflicts-multirepo'}
atf_test_program{name='create'}
atf_test_program{name='delete'}
atf_test_program{name='lock'}
+
atf_test_program{name='messages'}
atf_test_program{name='packagesplit'}
atf_test_program{name='php-pr'}
atf_test_program{name='pkg'}
added tests/frontend/messages.sh
@@ -0,0 +1,95 @@
+
#! /usr/bin/env atf-sh
+

+
. $(atf_get_srcdir)/test_environment.sh
+

+
tests_init \
+
	messages
+

+
messages_body() {
+
	cat > test.ucl << EOF
+
name: "test"
+
origin: "test"
+
version: "5.20_3"
+
arch: "*"
+
maintainer: "none"
+
prefix: "/usr/local"
+
www: "unknown"
+
comment: "need one"
+
desc: "also need one"
+
message: [
+
	{ message: "Always print" },
+
	{ message: "package being removed", type: remove },
+
	{ message: "package being installed", type: install },
+
	{ message: "package is being upgraded", type: upgrade },
+
	{ message: "Upgrading from lower than 1.0", maximum_version: "1.0", type: upgrade },
+
	{ message: "Upgrading from higher than 1.0", minimum_version: "1.0", type: upgrade  },
+
	{ message: "Upgrading from >1.0 < 3.0", maximum_version: "3.0", minimum_version: "1.0", type: upgrade  }
+
]
+
EOF
+
	atf_check \
+
		-o match:".*Installing.*" \
+
		-o match:"^Always print.*" \
+
		-o match:"^package being installed.*" \
+
		pkg register -M test.ucl
+
	atf_check \
+
		-o match:"^package being removed.*" \
+
		pkg delete -y test
+

+
	cat << EOF > repo1.conf
+
local1: {
+
	url: file://${TMPDIR},
+
	enabled: true
+
}
+
EOF
+
	cat > test2.ucl << EOF
+
name: "test"
+
origin: "test"
+
version: "0.20_3"
+
arch: "*"
+
maintainer: "none"
+
prefix: "/usr/local"
+
www: "unknown"
+
comment: "need one"
+
desc: "also need one"
+
EOF
+
	atf_check -o ignore pkg register -M test2.ucl
+
	atf_check -o ignore pkg create -M test.ucl
+
	atf_check -o ignore pkg repo .
+
	atf_check -o match:"^Upgrading from lower than 1.0.*" \
+
	    pkg -o REPOS_DIR="${TMPDIR}" -o PKG_CACHEDIR="${TMPDIR}" upgrade -y
+
	atf_check -o ignore pkg delete -y test
+

+
	cat > test2.ucl << EOF
+
name: "test"
+
origin: "test"
+
version: "4.20_3"
+
arch: "*"
+
maintainer: "none"
+
prefix: "/usr/local"
+
www: "unknown"
+
comment: "need one"
+
desc: "also need one"
+
EOF
+
	atf_check -o ignore pkg register -M test2.ucl
+
	atf_check \
+
		-o match:"^Upgrading from higher than 1.0.*" \
+
	    pkg -o REPOS_DIR="${TMPDIR}" -o PKG_CACHEDIR="${TMPDIR}" upgrade -y
+
	atf_check -o ignore pkg delete -y test
+

+
	cat > test2.ucl << EOF
+
name: "test"
+
origin: "test"
+
version: "2.20_3"
+
arch: "*"
+
maintainer: "none"
+
prefix: "/usr/local"
+
www: "unknown"
+
comment: "need one"
+
desc: "also need one"
+
EOF
+
	atf_check -o ignore pkg register -M test2.ucl
+
	atf_check \
+
		-o match:"^Upgrading from >1.0 < 3.0.*" \
+
		-o match:"^Upgrading from higher than 1.0.*" \
+
		pkg -o REPOS_DIR="${TMPDIR}" -o PKG_CACHEDIR="${TMPDIR}" upgrade -y
+
}