Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add preliminary support for @config
Baptiste Daroussin committed 11 years ago
commit e6cd4064e4f4a62cae8d1cddbaeeda043e1fcadb
parent bfc0da2
9 files changed +188 -3
modified libpkg/pkg.c
@@ -478,6 +478,14 @@ pkg_files(const struct pkg *pkg, struct pkg_file **f)
}

int
+
pkg_config_files(const struct pkg *pkg, struct pkg_config_file **f)
+
{
+
	assert(pkg != NULL);
+

+
	HASH_NEXT(pkg->config_files, (*f));
+
}
+

+
int
pkg_dirs(const struct pkg *pkg, struct pkg_dir **d)
{
	assert(pkg != NULL);
@@ -754,6 +762,35 @@ pkg_addfile_attr(struct pkg *pkg, const char *path, const char *sha256, const ch
}

int
+
pkg_addconfig_file(struct pkg *pkg, const char *path, const char *content)
+
{
+
	struct pkg_config_file *f;
+
	char abspath[MAXPATHLEN];
+

+
	path = pkg_absolutepath(path, abspath, sizeof(abspath));
+
	pkg_debug(3, "Pkg: add new config file '%s'", path);
+

+
	HASH_FIND_STR(pkg->config_files, path, f);
+
	if (f != NULL) {
+
		if (pkg_object_bool(pkg_config_get("DEVELOPER_MODE"))) {
+
			pkg_emit_error("duplicate file listing: %s, fatal (developer mode)", f->path);
+
			return (EPKG_FATAL);
+
		} else {
+
			pkg_emit_error("duplicate file listing: %s, ignoring", f->path);
+
		}
+
	}
+
	pkg_config_file_new(&f);
+
	strlcpy(f->path, path, sizeof(f->path));
+

+
	if (content != NULL)
+
		f->content = strdup(content);
+

+
	HASH_ADD_STR(pkg->config_files, path, f);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_addcategory(struct pkg *pkg, const char *name)
{
	const pkg_object *o, *categories;
@@ -1296,6 +1333,8 @@ pkg_list_count(const struct pkg *pkg, pkg_list list)
		return (HASH_COUNT(pkg->conflicts));
	case PKG_PROVIDES:
		return (HASH_COUNT(pkg->provides));
+
	case PKG_CONFIG_FILES:
+
		return (HASH_COUNT(pkg->config_files));
	}
	
	return (0);
@@ -1317,7 +1356,9 @@ pkg_list_free(struct pkg *pkg, pkg_list list) {
		pkg->flags &= ~PKG_LOAD_OPTIONS;
		break;
	case PKG_FILES:
+
	case PKG_CONFIG_FILES:
		HASH_FREE(pkg->files, pkg_file_free);
+
		HASH_FREE(pkg->config_files, pkg_config_file_free);
		pkg->flags &= ~PKG_LOAD_FILES;
		break;
	case PKG_DIRS:
modified libpkg/pkg.h.in
@@ -90,6 +90,7 @@ struct pkg_user;
struct pkg_group;
struct pkg_shlib;
struct pkg_provide;
+
struct pkg_config_file;

struct pkgdb;
struct pkgdb_it;
@@ -299,7 +300,8 @@ typedef enum {
	PKG_SHLIBS_REQUIRED,
	PKG_SHLIBS_PROVIDED,
	PKG_CONFLICTS,
-
	PKG_PROVIDES
+
	PKG_PROVIDES,
+
	PKG_CONFIG_FILES,
} pkg_list;

typedef enum {
@@ -637,6 +639,13 @@ int pkg_conflicts(const struct pkg *pkg, struct pkg_conflict **conflict);
int pkg_provides(const struct pkg *pkg, struct pkg_provide **provide);

/**
+
 * Iterates over the config files registered in the package.
+
 * @param provide must be set to NULL for the first call.
+
 * @return An error code
+
 */
+
int pkg_config_files(const struct pkg *pkg, struct pkg_config_file **cf);
+

+
/**
 * Iterate over all of the files within the package pkg, ensuring the
 * dependency list contains all applicable packages providing the
 * shared objects used by pkg.
modified libpkg/pkg_attributes.c
@@ -332,3 +332,25 @@ pkg_provide_name(const struct pkg_provide *c)

	return (sbuf_get(c->provide));
}
+

+
/*
+
 * Config files
+
 */
+
int
+
pkg_config_file_new(struct pkg_config_file **c)
+
{
+
	if ((*c = calloc(1, sizeof(struct pkg_config_file))) == NULL)
+
		return (EPKG_FATAL);
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_config_file_free(struct pkg_config_file *c)
+
{
+
	if (c == NULL)
+
		return;
+

+
	free(c->content);
+
	free(c);
+
}
modified libpkg/pkg_manifest.c
@@ -81,6 +81,7 @@ static struct manifest_key {
	{ "categories",          PKG_CATEGORIES,          UCL_ARRAY,  pkg_array},
	{ "comment",             PKG_COMMENT,             UCL_STRING, pkg_string},
	{ "conflicts",           PKG_CONFLICTS,           UCL_ARRAY,  pkg_array},
+
	{ "config",              PKG_CONFIG_FILES,        UCL_ARRAY,  pkg_array},
	{ "deps",                PKG_DEPS,                UCL_OBJECT, pkg_obj},
	{ "desc",                PKG_DESC,                UCL_STRING, pkg_string},
	{ "directories",         PKG_DIRECTORIES,         UCL_OBJECT, pkg_obj},
@@ -376,6 +377,12 @@ pkg_array(struct pkg *pkg, const ucl_object_t *obj, int attr)
			else
				pkg_addprovide(pkg, ucl_object_tostring(cur));
			break;
+
		case PKG_CONFIG_FILES:
+
			if (cur->type != UCL_STRING)
+
				pkg_emit_error("Skipping malformed config file name");
+
			else
+
				pkg_addconfig_file(pkg, ucl_object_tostring(cur), NULL);
+
			break;
		}
	}

@@ -872,6 +879,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	struct pkg_shlib	*shlib    = NULL;
	struct pkg_conflict	*conflict = NULL;
	struct pkg_provide	*provide  = NULL;
+
	struct pkg_config_file	*cf       = NULL;
	struct sbuf		*tmpsbuf  = NULL;
	int i;
	const char *comment, *desc, *message, *repopath, *abi;
@@ -1086,6 +1094,18 @@ pkg_emit_object(struct pkg *pkg, short flags)
			if (map)
				ucl_object_insert_key(top, map, "files", 5, false);

+
			pkg_debug(3, "Emitting config files");
+
			seq = NULL;
+
			while (pkg_config_files(pkg, &cf) == EPKG_OK) {
+
				urlencode(cf->path, &tmpsbuf);
+
				if (seq == NULL)
+
					seq = ucl_object_typed_new(UCL_ARRAY);
+
				printf("%s\n", cf->path);
+
				ucl_array_append(seq, ucl_object_fromstring(sbuf_data(tmpsbuf)));
+
			}
+
			if (seq)
+
				ucl_object_insert_key(top, seq, "config", 6, false);
+

			pkg_debug(4, "Emitting directories");
			map = NULL;
			while (pkg_dirs(pkg, &dir) == EPKG_OK) {
modified libpkg/pkg_ports.c
@@ -56,6 +56,7 @@ static int setowner(struct plist *, char *, struct file_attr *);
static int setgroup(struct plist *, char *, struct file_attr *);
static int ignore_next(struct plist *, char *, struct file_attr *);
static int comment_key(struct plist *, char *, struct file_attr *);
+
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 pkgdep(struct plist *, char *, struct file_attr *);
@@ -75,6 +76,7 @@ static struct action_cmd {
	{ "setgroup", setgroup, 8 },
	{ "comment", comment_key, 7 },
	{ "ignore_next", ignore_next, 11 },
+
	{ "config", config, 6 },
	/* compat with old packages */
	{ "name", name_key, 4 },
	{ "pkgdep", pkgdep, 6 },
@@ -307,7 +309,7 @@ dirrm(struct plist *p, char *line, struct file_attr *a)
}

static int
-
file(struct plist *p, char *line, struct file_attr *a)
+
meta_file(struct plist *p, char *line, struct file_attr *a, bool is_config)
{
	size_t len;
	char path[MAXPATHLEN];
@@ -372,6 +374,18 @@ file(struct plist *p, char *line, struct file_attr *a)
			else
				sha256_file(testpath, sha256);
			buf = sha256;
+
			if (is_config) {
+
				size_t sz;
+
				char *content;
+
				file_to_buffer(testpath, &content, &sz);
+
				pkg_addconfig_file(p->pkg, path, content);
+
				free(content);
+
			}
+
		} else {
+
			if (is_config) {
+
				pkg_emit_error("Plist error, @config %s: not a regular file", line);
+
				return (EPKG_FATAL);
+
			}
		}
		if (S_ISDIR(st.st_mode) &&
		    !pkg_object_bool(pkg_config_get("PLIST_ACCEPT_DIRECTORIES"))) {
@@ -407,6 +421,18 @@ file(struct plist *p, char *line, struct file_attr *a)
}

static int
+
config(struct plist *p, char *line, struct file_attr *a)
+
{
+
	return (meta_file(p, line, a, true));
+
}
+

+
static int
+
file(struct plist *p, char *line, struct file_attr *a)
+
{
+
	return (meta_file(p, line, a, false));
+
}
+

+
static int
setmod(struct plist *p, char *line, struct file_attr *a)
{
	void *set;
@@ -708,6 +734,7 @@ static struct keyact {
	{ "cwd", setprefix },
	{ "ignore", ignore_next },
	{ "comment", comment_key },
+
	{ "config", config },
	{ "dir", dir },
	{ "dirrm", dirrm },
	{ "dirrmtry", dirrm },
modified libpkg/pkgdb.c
@@ -73,7 +73,7 @@
*/

#define DB_SCHEMA_MAJOR	0
-
#define DB_SCHEMA_MINOR	27
+
#define DB_SCHEMA_MINOR	28

#define DBVERSION (DB_SCHEMA_MAJOR * 1000 + DB_SCHEMA_MINOR)

@@ -512,6 +512,12 @@ pkgdb_init(sqlite3 *sdb)
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
	    "UNIQUE(package_id, provide_id)"
	");"
+
	"CREATE TABLE config_files ("
+
		"path TEXT NOT NULL UNIQUE, "
+
		"content TEXT, "
+
		"package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE"
+
			" ON UPDATE CASCADE"
+
	");"

	/* FTS search table */

@@ -1231,6 +1237,7 @@ typedef enum _sql_prstmt_index {
	PROVIDE,
	FTS_APPEND,
	UPDATE_DIGEST,
+
	CONFIG_FILES,
	PRSTMT_LAST,
} sql_prstmt_index;

@@ -1438,6 +1445,12 @@ static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
		NULL,
		"UPDATE packages SET manifestdigest=?1 WHERE id=?2;",
		"TI"
+
	},
+
	[CONFIG_FILES] = {
+
		NULL,
+
		"INSERT INTO config_files(path, content, package_id) "
+
		"VALUES (?1, ?2, ?3);",
+
		"TTI"
	}
	/* PRSTMT_LAST */
};
@@ -1532,6 +1545,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete, int forced)
	struct pkg_user		*user = NULL;
	struct pkg_group	*group = NULL;
	struct pkg_conflict	*conflict = NULL;
+
	struct pkg_config_file	*cf = NULL;
	struct pkgdb_it		*it = NULL;
	const pkg_object	*obj;
	pkg_iter		 iter;
@@ -1702,6 +1716,20 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete, int forced)
		pkgdb_it_free(it);
	}

+
	/* Insert config files */
+
	while (pkg_config_files(pkg, &cf) == EPKG_OK)
+
	{
+
		if ((ret = run_prstmt(CONFIG_FILES, cf->path, cf->content, package_id)
+
		    != SQLITE_DONE)) {
+
			if (ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_error("Another package already owns :%s",
+
				    cf->path);
+
			} else
+
				ERROR_SQLITE(s, SQL(CONFIG_FILES));
+
			goto cleanup;
+
		}
+
	}
+

	/*
	 * Insert dirs.
	 */
modified libpkg/pkgdb_iterator.c
@@ -293,6 +293,11 @@ pkgdb_load_files(sqlite3 *sqlite, struct pkg *pkg)
		"FROM files "
		"WHERE package_id = ?1 "
		"ORDER BY PATH ASC";
+
	const char	 sql2[] = ""
+
		"SELECT path, content "
+
		"FROM config_files "
+
		"WHERE package_id = ?1 "
+
		"ORDER BY PATH ASC";

	assert( pkg != NULL);
	assert(pkg->type == PKG_INSTALLED);
@@ -315,6 +320,20 @@ pkgdb_load_files(sqlite3 *sqlite, struct pkg *pkg)
	}
	sqlite3_finalize(stmt);

+
	pkg_debug(4, "Pkgdb: running '%s'", sql2);
+
	if (sqlite3_prepare_v2(sqlite, sql2, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(sqlite, sql2);
+
		return (EPKG_FATAL);
+
	}
+

+
	sqlite3_bind_int64(stmt, 1, rowid);
+

+
	while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) {
+
		pkg_addconfig_file(pkg, sqlite3_column_text(stmt, 0),
+
		    sqlite3_column_text(stmt, 1));
+
	}
+

+
	sqlite3_finalize(stmt);
	if (ret != SQLITE_DONE) {
		pkg_list_free(pkg, PKG_FILES);
		ERROR_SQLITE(sqlite, sql);
modified libpkg/private/db_upgrades.h
@@ -635,6 +635,14 @@ static struct db_upgrades {
	"CREATE INDEX IF NOT EXISTS packages_uid ON packages(name, origin COLLATE NOCASE);"
	"CREATE INDEX IF NOT EXISTS packages_version ON packages(name, version);"
	},
+
	{28,
+
	"CREATE TABLE config_files ("
+
		"path TEXT NOT NULL UNIQUE, "
+
		"content TEXT, "
+
		"package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE"
+
			" ON UPDATE CASCADE"
+
	");"
+
	},
	/* Mark the end of the array */
	{ -1, NULL }

modified libpkg/private/pkg.h
@@ -135,6 +135,7 @@ struct pkg {
	struct pkg_shlib	*shlibs_provided;
	struct pkg_conflict *conflicts;
	struct pkg_provide	*provides;
+
	struct pkg_config_file	*config_files;
	unsigned			flags;
	int		rootfd;
	char		rootpath[MAXPATHLEN];
@@ -399,6 +400,12 @@ struct action {
	struct action *next;
};

+
struct pkg_config_file {
+
	char path[MAXPATHLEN];
+
	char *content;
+
	UT_hash_handle hh;
+
};
+

/* sql helpers */

typedef struct _sql_prstmt {
@@ -504,6 +511,9 @@ void pkg_conflict_free(struct pkg_conflict *);
int pkg_provide_new(struct pkg_provide **);
void pkg_provide_free(struct pkg_provide *);

+
int pkg_config_file_new(struct pkg_config_file **);
+
void pkg_config_file_free(struct pkg_config_file *);
+

struct packing;

int packing_init(struct packing **pack, const char *path, pkg_formats format,
@@ -598,6 +608,7 @@ int pkg_addshlib_required(struct pkg *pkg, const char *name);
int pkg_addshlib_provided(struct pkg *pkg, const char *name);
int pkg_addconflict(struct pkg *pkg, const char *name);
int pkg_addprovide(struct pkg *pkg, const char *name);
+
int pkg_addconfig_file(struct pkg *pkg, const char *name, const char *buf);

int pkg_addoption(struct pkg *pkg, const char *name, const char *value);
int pkg_addoption_default(struct pkg *pkg, const char *key, const char *default_value);