Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add initial API for repo metadata.
Vsevolod Stakhov committed 12 years ago
commit 1e87ff1ece500e7b8a4e7a5ab9433f330f614e02
parent 5ba65fe
3 files changed +269 -0
modified libpkg/Makefile.am
@@ -30,6 +30,7 @@ libpkg_la_SOURCES= pkg.c \
			pkg_repo.c \
			pkg_repo_create.c \
			pkg_repo_update.c \
+
			pkg_repo_meta.c \
			pkg_solve.c \
			pkg_status.c \
			pkg_version.c \
added libpkg/pkg_repo_meta.c
@@ -0,0 +1,243 @@
+
/*-
+
 * Copyright (c) 2014 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
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer
+
 *    in this position and unchanged.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include <ucl.h>
+

+
#include "pkg.h"
+
#include "private/event.h"
+
#include "private/pkg.h"
+

+
static ucl_object_t *repo_meta_schema_v1 = NULL;
+

+
static void
+
pkg_repo_meta_set_default(struct pkg_repo_meta *meta)
+
{
+
	meta->digest_format = strdup("sha256");
+
	meta->packing_format = TXZ;
+

+
	/* Not use conflicts for now */
+
	meta->conflicts = NULL;
+
	meta->manifests = strdup("manifests");
+
	meta->digests = strdup("digests");
+
	/* Not using fulldb */
+
	meta->fulldb = NULL;
+
}
+

+
void
+
pkg_repo_meta_free(struct pkg_repo_meta *meta)
+
{
+
	if (meta != NULL) {
+
		free(meta->conflicts);
+
		free(meta->manifests);
+
		free(meta->digests);
+
		free(meta->fulldb);
+
		free(meta->digest_format);
+
		free(meta->maintainer);
+
		free(meta->source);
+
		free(meta->source_identifier);
+
		free(meta);
+
	}
+
}
+

+
static ucl_object_t*
+
pkg_repo_meta_open_schema_v1()
+
{
+
	struct ucl_parser *parser;
+
	static const char meta_schema_str_v1[] = ""
+
			"{"
+
			"type = object;"
+
			"properties {"
+
			"version = {type = integer};\n"
+
			"maintainer = {type = string};\n"
+
			"source = {type = string};\n"
+
			"packing_format = {enum = [txz, tbz, tgz]};\n"
+
			"digest_format = {enum = [sha256]};\n"
+
			"digests = {type = string};\n"
+
			"manifests = {type = string};\n"
+
			"conflicts = {type = string};\n"
+
			"fulldb = {type = string};\n"
+
			"source_identifier = {type = string};\n"
+
			"revision = {type = integer};\n"
+
			"eol = {type = integer};\n"
+
			"}\n"
+
			"required = [version]\n"
+
			"}";
+

+
	if (repo_meta_schema_v1 != NULL)
+
		return (repo_meta_schema_v1);
+

+
	parser = ucl_parser_new(0);
+
	if (!ucl_parser_add_chunk(parser, meta_schema_str_v1,
+
			sizeof(meta_schema_str_v1) - 1)) {
+
		pkg_emit_error("cannot parse schema for repo meta: %s",
+
				ucl_parser_get_error(parser));
+
		ucl_parser_free(parser);
+
		return (NULL);
+
	}
+

+
	repo_meta_schema_v1 = ucl_parser_get_object(parser);
+
	ucl_parser_free(parser);
+

+
	return (repo_meta_schema_v1);
+
}
+

+
#define META_EXTRACT_STRING(field) do { 						\
+
	obj = ucl_object_find_key(top, (#field)); 					\
+
	if (obj != NULL && obj->type == UCL_STRING) { 				\
+
	    if (meta->field != NULL) 								\
+
	    	free(meta->field);									\
+
	    meta->field = strdup(ucl_object_tostring(obj));			\
+
	}															\
+
} while (0)
+

+
static int
+
pkg_repo_meta_parse(ucl_object_t *top, struct pkg_repo_meta **target, int version)
+
{
+
	ucl_object_t *obj;
+
	struct pkg_repo_meta *meta;
+

+
	meta = calloc(1, sizeof(*meta));
+
	if (meta == NULL) {
+
		pkg_emit_errno("pkg_repo_meta_parse", "malloc failed for pkg_repo_meta");
+
		return (EPKG_FATAL);
+
	}
+

+
	pkg_repo_meta_set_default(meta);
+

+
	META_EXTRACT_STRING(maintainer);
+
	META_EXTRACT_STRING(source);
+
	META_EXTRACT_STRING(digest_format);
+

+
	META_EXTRACT_STRING(conflicts);
+
	META_EXTRACT_STRING(digests);
+
	META_EXTRACT_STRING(manifests);
+
	META_EXTRACT_STRING(fulldb);
+

+
	META_EXTRACT_STRING(source_identifier);
+

+
	obj = ucl_object_find_key(top, "eol");
+
	if (obj != NULL && obj->type == UCL_INT) {
+
		meta->eol = ucl_object_toint(obj);
+
	}
+

+
	obj = ucl_object_find_key(top, "revision");
+
	if (obj != NULL && obj->type == UCL_INT) {
+
		meta->revision = ucl_object_toint(obj);
+
	}
+

+
	obj = ucl_object_find_key(top, "packing_format");
+
	if (obj != NULL && obj->type == UCL_STRING) {
+
		meta->packing_format = packing_format_from_string(ucl_object_tostring(obj));
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
#undef META_EXTRACT_STRING
+

+
static int
+
pkg_repo_meta_version(ucl_object_t *top)
+
{struct pkg_repo_meta *meta;
+

+
meta = calloc(1, sizeof(*meta));
+
if (meta == NULL) {
+
	pkg_emit_errno("pkg_repo_meta_parse", "malloc failed for pkg_repo_meta");
+
	return (EPKG_FATAL);
+
}
+
	ucl_object_t *obj;
+

+
	if ((obj = ucl_object_find_key(top, "version")) != NULL) {
+
		if (obj->type == UCL_INT) {
+
			return (ucl_object_toint(obj));
+
		}
+
	}
+

+
	return (-1);
+
}
+

+
int
+
pkg_repo_meta_load(const char *file, struct pkg_repo_meta **target)
+
{
+
	struct ucl_parser *parser;
+
	ucl_object_t *top, *schema;
+
	struct ucl_schema_error err;
+
	int version;
+

+
	parser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE);
+

+
	if (!ucl_parser_add_file(parser, file)) {
+
		pkg_emit_error("cannot parse repository meta from %s: %s", file,
+
				ucl_parser_get_error(parser));
+
		ucl_parser_free(parser);
+
		return (EPKG_FATAL);
+
	}
+

+
	top = ucl_parser_get_object(parser);
+
	ucl_parser_free(parser);
+

+
	version = pkg_repo_meta_version(top);
+
	if (version == -1) {
+
		pkg_emit_error("repository meta %s has wrong version or wrong format", file);
+
		ucl_object_unref(top);
+
		return (EPKG_FATAL);
+
	}
+

+
	/* Now we support only v1 meta */
+
	if (version == 1) {
+
		schema = pkg_repo_meta_open_schema_v1();
+

+
		if (schema != NULL) {
+
			if (!ucl_object_validate(schema, top, &err)) {
+
				pkg_emit_error("repository meta %s cannot be validated: %s", file, err.msg);
+
				ucl_object_unref(top);
+
				return (EPKG_FATAL);
+
			}
+
		}
+
	}
+
	else {
+
		pkg_emit_error("repository meta %s has wrong version %d", file, version);
+
		ucl_object_unref(top);
+
		return (EPKG_FATAL);
+
	}
+

+
	return (pkg_repo_meta_parse(top, target, version));
+
}
+

+
struct pkg_repo_meta *
+
pkg_repo_meta_default(void)
+
{
+
	struct pkg_repo_meta *meta;
+

+
	meta = calloc(1, sizeof(*meta));
+
	if (meta == NULL) {
+
		pkg_emit_errno("pkg_repo_meta_default", "malloc failed for pkg_repo_meta");
+
		return (NULL);
+
	}
+

+
	pkg_repo_meta_set_default(meta);
+

+
	return (meta);
+
}
modified libpkg/private/pkg.h
@@ -277,6 +277,25 @@ struct http_mirror {
	struct http_mirror *next;
};

+
struct pkg_repo_meta {
+

+
	char *maintainer;
+
	char *source;
+

+
	pkg_formats packing_format;
+
	char *digest_format; /* TODO: should be enumeration */
+

+
	char *digests;
+
	char *manifests;
+
	char *conflicts;
+
	char *fulldb;
+

+
	char *source_identifier;
+
	int64_t revision;
+

+
	time_t eol;
+
};
+

struct pkg_repo {
	repo_t type;
	char *name;
@@ -297,6 +316,8 @@ struct pkg_repo {
		pid_t pid;
	} sshio;

+
	struct pkg_repo_meta *meta;
+

	int (*update)(struct pkg_repo *, bool);

	bool enable;
@@ -341,6 +362,10 @@ int pkg_repo_fetch_package(struct pkg *pkg);
FILE * pkg_repo_fetch_remote_extract_tmp(struct pkg_repo *repo, const char *filename,
		const char *extension, time_t *t, int *rc, const char *archive_file);

+
struct pkg_repo_meta *pkg_repo_meta_default(void);
+
int pkg_repo_meta_load(const char *file, struct pkg_repo_meta **target);
+
void pkg_repo_meta_free(struct pkg_repo_meta *meta);
+

typedef enum {
	HASH_UNKNOWN,
	HASH_SHA256,