Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
plist: grow the notion of variable
Baptiste Daroussin committed 2 years ago
commit a340f7855f2f901b90fce56319daee193d313370
parent df217a9
4 files changed +135 -1
modified libpkg/pkg_ports.c
@@ -68,6 +68,7 @@ static int config(struct plist *, char *, struct file_attr *);
/* compat with old packages */
static int name_key(struct plist *, char *, struct file_attr *);
static int include_plist(struct plist *, char *, struct file_attr *);
+
static int add_variable(struct plist *, char *, struct file_attr *);

static struct action_cmd {
	const char *name;
@@ -477,6 +478,7 @@ static struct keyact {
	{ "owner", setowner },
	{ "group", setgroup },
	{ "override_prefix", override_prefix },
+
	{ "var", add_variable },
	/* old pkg compat */
	{ "name", name_key },
	{ NULL, NULL },
@@ -1077,6 +1079,64 @@ plist_free(struct plist *p)
	free(p);
}

+
static char *
+
expand_plist_variables(const char *in, kvlist_t *vars)
+
{
+
	xstring *buf;
+
	const char *cp;
+
	size_t len;
+

+
	if (tll_length(*vars) == 0)
+
		return (xstrdup(in));
+

+
	buf = xstring_new();
+
	cp = NULL;
+
	while (in[0] != '\0') {
+
		if (in[0] != '%') {
+
			fputc(in[0], buf->fp);
+
			in++;
+
			continue;
+
		}
+
		in++;
+
		if (in[0] == '\0')
+
			break;
+
		if (in[0] != '%') {
+
			fputc(in[0], buf->fp);
+
			in++;
+
			continue;
+
		}
+
		in++;
+
		cp = in;
+
		while (in[0] != '\0' && !isspace(in[0])) {
+
			if (in[0] == '%' && in[1] == '%') {
+
				in++;
+
				break;
+
			}
+
			in++;
+
		}
+
		if (in[0] != '%') {
+
			fprintf(buf->fp, "%%%%%.*s", (int)(in - cp), cp);
+
			in++;
+
			continue;
+
		}
+
		len = in - cp -1;
+
		/* we have a variable */
+
		bool found = false;
+
		tll_foreach(*vars, i) {
+
			if (strncmp(cp, i->item->key, len) != 0)
+
				continue;
+
			fputs(i->item->value, buf->fp);
+
			found = true;
+
			break;
+
		}
+
		if (found)
+
			continue;
+
		fprintf(buf->fp, "%%%%%.*s%%", (int)(in - cp), cp);
+
		in++;
+
	}
+
	return (xstring_get(buf));
+
}
+

static int
plist_parse(struct plist *pplist, FILE *f)
{
@@ -1084,11 +1144,14 @@ plist_parse(struct plist *pplist, FILE *f)
	size_t linecap = 0;
	ssize_t linelen;
	char *line = NULL;
+
	char *l;

	while ((linelen = getline(&line, &linecap, f)) > 0) {
		if (line[linelen - 1] == '\n')
			line[linelen - 1] = '\0';
-
		ret = plist_parse_line(pplist, line);
+
		l = expand_plist_variables(line, &pplist->variables);
+
		ret = plist_parse_line(pplist, l);
+
		free(l);
		if (ret != EPKG_OK && rc == EPKG_OK)
			rc = ret;
	}
@@ -1117,6 +1180,40 @@ open_directory_of(const char *file)
}

int
+
add_variable(struct plist *p, char *line, struct file_attr *a __unused)
+
{
+
	const char *key;
+
	char *val;
+

+
	key = val = line;
+
	while (*val != '\0' && !isspace(*val))
+
		val++;
+
	if (*val != '\0') {
+
		*val = '\0';
+
		val++;
+
	}
+

+
	if (*key == '\0') {
+
		pkg_emit_error("Inside in @include it is not allowed to reuse @include");
+
		return (EPKG_FATAL);
+
	}
+

+
	while (*val != '\0' && isspace(*val))
+
		val++;
+

+
	tll_foreach(p->variables, v) {
+
		if (strcmp(v->item->key, key) == 0) {
+
			free(v->item->value);
+
			v->item->value = xstrdup(val);
+
			return (EPKG_OK);
+
		}
+
	}
+
	struct pkg_kv *kv = pkg_kv_new(key, val);
+
	tll_push_back(p->variables, kv);
+
	return (EPKG_OK);
+
}
+

+
int
include_plist(struct plist *p, char *name, struct file_attr *a __unused)
{
	FILE *f;
modified libpkg/private/pkg.h
@@ -599,6 +599,7 @@ struct plist {
	hardlinks_t hardlinks;
	mode_t perm;
	pkghash *keywords;
+
	kvlist_t variables;
};

struct file_attr {
modified libpkg/utils.c
@@ -57,6 +57,7 @@
#include "private/utils.h"
#include "private/pkg.h"
#include "xmalloc.h"
+
#include "tllist.h"

extern struct pkg_ctx ctx;

modified tests/frontend/create.sh
@@ -4,6 +4,7 @@

tests_init \
	create_from_plist \
+
	create_from_plist_with_variables \
	create_from_plist_set_owner \
	create_from_plist_set_group_space \
	create_from_plist_gather_mode \
@@ -818,3 +819,37 @@ create_from_plist_keyword_override_prefix_body()
	atf_check -o match:".*/plop/file$" -e ignore tar tf test-1.pkg
	atf_check -o inline:"/plop/file\n" pkg info -F test-1.pkg -ql
}
+

+

+
create_from_plist_with_variables_body() {
+
	touch file1 file2 plop file3
+
	genmanifest
+
	genplist "
+
@var key1
+
@var key2 
+
@var key3 plop
+
%%key1%%file1
+
%%key2%%file2
+
%%key3%%
+
@var key3 @comment 
+
%%key3%% file3"
+

+
	atf_check \
+
		-o empty \
+
		-e empty \
+
		-s exit:0 \
+
		pkg create -o ${TMPDIR} -m . -p test.plist -r .
+

+
	basic_validation
+
	atf_check \
+
		-o inline:"/file1\n/file2\n/plop\n" \
+
		 pkg info -F test-1.pkg -ql
+
	rm test-1.pkg
+
	echo "
+
%%plop%%
+
" >> test.plist
+
	atf_check \
+
		-e match:"%%plop%%" \
+
		-s exit:1 \
+
		pkg create -o ${TMPDIR} -m . -p test.plist -r .
+
}