Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
New pkg query -e <evaluation> <query-format>
Baptiste Daroussin committed 14 years ago
commit 5a0ae305dfb03bb44af4c80d9acd180e73caefcb
parent f39b5d8
4 files changed +251 -3
modified libpkg/pkg.h
@@ -573,6 +573,7 @@ int pkgdb_unregister_pkg(struct pkgdb *pkg, const char *origin);
 */
struct pkgdb_it * pkgdb_query(struct pkgdb *db, const char *pattern,
							  match_t type);
+
struct pkgdb_it * pkgdb_query_condition(struct pkgdb *db, const char *condition);
struct pkgdb_it * pkgdb_rquery(struct pkgdb *db, const char *pattern,
		match_t type, unsigned int field, const char *reponame);

modified libpkg/pkgdb.c
@@ -772,6 +772,30 @@ pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
}

struct pkgdb_it *
+
pkgdb_query_condition(struct pkgdb *db, const char *condition)
+
{
+
	char sql[BUFSIZ];
+
	sqlite3_stmt *stmt;
+

+
	assert(db != NULL);
+
	assert (condition != NULL);
+

+
	snprintf(sql, sizeof(sql),
+
	    "SELECT id, origin, name, version, comment, desc, "
+
	        "message, arch, osversion, maintainer, www, "
+
	        "prefix, flatsize, licenselogic, automatic "
+
	    "FROM packages AS p WHERE %s "
+
	    "ORDER BY p.name;", condition);
+

+
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (NULL);
+
	}
+

+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
+
}
+

+
struct pkgdb_it *
pkgdb_query_which(struct pkgdb *db, const char *path)
{
	sqlite3_stmt *stmt;
modified pkg/pkg-query.8
@@ -15,7 +15,7 @@
.\"     @(#)pkg.8
.\" $FreeBSD$
.\"
-
.Dd February 16, 2012
+
.Dd March 2, 2012
.Dt PKG-QUERY 8
.Os
.Sh NAME
@@ -27,6 +27,8 @@
.Nm
.Fl f Ao pkg-name Ac Ao query-format Ac
.Nm
+
.Fl e Ao evaluation-condition Ac Ao query-format Ac
+
.Nm
.Op Fl gxX
.Ao query-format Ac Ao pattern Ac Ao ... Ac
.Sh DESCRIPTION
@@ -147,6 +149,38 @@ Expands to the list of groups needed by the matched package.
.It Cm \&%S
Expands to the list of scripts for the matching packages - install, deinstall, etc.
.El
+
.Sh EVALUATION FORMAT
+
.Ss Variables
+
.Bl -tag -width F1
+
.It Cm \&%n
+
Name of the package (type string)
+
.It Cm \&%o
+
Origin of the package (type string)
+
.It Cm \&%p
+
Prefix of the package (type string)
+
.It Cm \&%m
+
Maintainer of the package (type string)
+
.It Cm \&%c
+
Comment of the package (type string)
+
.It Cm \&%w
+
WWW address of the package (type string)
+
.It Cm \&%s
+
Flatsize of the package (type integer)
+
.It Cm \&%a
+
Automatic status of the package (type integer)
+
.It Cm \&%M
+
Message of the package (type string)
+
.El
+
.Ss Operators
+
.Bl -tag -width F1
+
.It Cm ~
+
String glob pattern matching
+
.It Cm > Ns Op =
+
Integer comparison
+
.It Cm > Ns Op =
+
Integer comparison
+
.It Cm = Ns Op =
+
Integer or string comparison
.Sh ENVIRONMENT
The following environment variables affect the execution of
.Nm .
modified pkg/query.c
@@ -1,6 +1,7 @@
#include <sys/types.h>
#include <sys/sbuf.h>

+
#include <ctype.h>
#include <err.h>
#include <inttypes.h>
#include <libutil.h>
@@ -43,6 +44,18 @@ static struct query_flags {
        { 'M', "",		0, PKG_LOAD_BASIC },
};

+
typedef enum {
+
	NONE,
+
	NEXT_IS_INT,
+
	OPERATOR_INT,
+
	INT,
+
	NEXT_IS_STRING,
+
	OPERATOR_STRING,
+
	STRING,
+
	QUOTEDSTRING,
+
	SQUOTEDSTRING
+
} type_t;
+

const unsigned int flags_len = (sizeof(q_flags)/sizeof(q_flags[0]));

static void
@@ -321,6 +334,154 @@ print_query(struct pkg *pkg, char *qstr, char multiline)
	}
	sbuf_delete(output);
}
+

+
static int
+
format_sql_condition(const char *str, struct sbuf *sqlcond)
+
{
+
	type_t state = NONE;
+
	while (str[0] != '\0') {
+
		if (state == NONE) {
+
			if (str[0] == '%') {
+
				str++;
+
				switch (str[0]) {
+
					case 'n':
+
						sbuf_cat(sqlcond, "name");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 'o':
+
						sbuf_cat(sqlcond, "origin");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 'p':
+
						sbuf_cat(sqlcond, "prefix");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 'm':
+
						sbuf_cat(sqlcond, "maintainer");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 'c':
+
						sbuf_cat(sqlcond, "comment");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 'w':
+
						sbuf_cat(sqlcond, "www");
+
						state = OPERATOR_STRING;
+
						break;
+
					case 's':
+
						sbuf_cat(sqlcond, "flatsize");
+
						state = OPERATOR_INT;
+
						break;
+
					case 'a':
+
						sbuf_cat(sqlcond, "automatic");
+
						state = OPERATOR_INT;
+
						break;
+
					case 'M':
+
						sbuf_cat(sqlcond, "message");
+
						state = OPERATOR_STRING;
+
						break;
+
					default:
+
						fprintf(stderr, "malformed evaluation string");
+
						return (EPKG_FATAL);
+
				}
+
			} else {
+
				if (str[0] == '|' && str[1] == '|') {
+
					str++;
+
					sbuf_cat(sqlcond, " OR ");
+
				} else if (str[0] == '&' && str[1] == '&') {
+
					str++;
+
					sbuf_cat(sqlcond, " AND ");
+
				} else {
+
					sbuf_putc(sqlcond, str[0]);
+
				}
+
			}
+
		} else if (state == OPERATOR_STRING || state == OPERATOR_INT) {
+
			/* only operators or space are allowed here */
+
			if (isspace(str[0])) {
+
				sbuf_putc(sqlcond, str[0]);
+
			} else if (str[0] == '~' ) {
+
				if (state != OPERATOR_STRING) {
+
					fprintf(stderr, "~ expected only for string testing");
+
					return (EPKG_FATAL);
+
				}
+
				state = NEXT_IS_STRING;
+
				sbuf_cat(sqlcond, " GLOB ");
+
			} else if (str[0] == '>' || str[0] == '<') {
+
				if (state != OPERATOR_INT) {
+
					fprintf(stderr, "> expected only for integers");
+
					return (EPKG_FATAL);
+
				}
+
				state = NEXT_IS_INT;
+
				sbuf_putc(sqlcond, str[0]);
+
				if (str[1] == '=') {
+
					str++;
+
					sbuf_putc(sqlcond, str[0]);
+
				}
+
			} else if (str[0] == '=') {
+
				if (state == OPERATOR_STRING) {
+
					state = NEXT_IS_STRING;
+
				} else {
+
					state = NEXT_IS_INT;
+
				}
+
				sbuf_putc(sqlcond, str[0]);
+
				if (str[1] == '=') {
+
					str++;
+
					sbuf_putc(sqlcond, str[0]);
+
				}
+
			}
+
		} else if (state == NEXT_IS_STRING || state == NEXT_IS_INT) {
+
			if (isspace(str[0])) {
+
				sbuf_putc(sqlcond, str[0]);
+
			} else {
+
				if (state == NEXT_IS_STRING) {
+
					if (str[0] == '"') {
+
						state = QUOTEDSTRING;
+
					} else if (str[0] == '\'') {
+
						state = SQUOTEDSTRING;
+
					} else {
+
						sbuf_putc(sqlcond, '"');
+
						state = STRING;
+
					}
+
					sbuf_putc(sqlcond, str[0]);
+
				} else {
+
					if (!isnumber(str[0])) {
+
						fprintf(stderr, "a number is expected got %c\n", str[0]);
+
						return (EPKG_FATAL);
+
					}
+
					state = INT;
+
					sbuf_putc(sqlcond, str[0]);
+
				}
+
			}
+
		} else if (state == INT) {
+
			if (isspace(str[0])) {
+
				state = NONE;
+
			} else if (!isnumber(str[0])) {
+
				fprintf(stderr, "a number is expected %c\n", str[0]);
+
				return (EPKG_FATAL);
+
			}
+
			sbuf_putc(sqlcond, str[0]);
+
		} else if ( state == STRING ) {
+
			if (isspace(str[0])) {
+
				sbuf_putc(sqlcond, '"');
+
				state = NONE;
+
			}
+
			sbuf_putc(sqlcond, str[0]);
+
		} else if (state == QUOTEDSTRING) {
+
			if (str[0] == '"')
+
				state = NONE;
+
			sbuf_putc(sqlcond, str[0]);
+
		} else if (state == SQUOTEDSTRING) {
+
			if (str[0] == '"')
+
				state = NONE;
+
			sbuf_putc(sqlcond, str[0]);
+
		}
+
		str++;
+
	}
+
	if (state == STRING)
+
		sbuf_putc(sqlcond, '"');
+
	return (EPKG_OK);
+
}
+

static int
analyse_query_string(char *qstr, int *flags, char *multiline)
{
@@ -405,6 +566,7 @@ usage_query(void)
{
	fprintf(stderr, "usage: pkg query -a <query-format>\n");
	fprintf(stderr, "       pkg query -f <pkg-name> <query-format>\n");
+
	fprintf(stderr, "       pkg query -e <evaluation> <query-format>\n");
	fprintf(stderr, "       pkg query [-gxX] <query-format> <pattern> <...>\n\n");
	fprintf(stderr, "For more information see 'pkg help query.'\n");
}
@@ -423,8 +585,10 @@ exec_query(int argc, char **argv)
	int retcode = EXIT_SUCCESS;
	int i;
	char multiline = 0;
+
	char *condition = NULL;
+
	struct sbuf *sqlcond = NULL;

-
	while ((ch = getopt(argc, argv, "agxXf:")) != -1) {
+
	while ((ch = getopt(argc, argv, "agxXf:e:")) != -1) {
		switch (ch) {
			case 'a':
				match = MATCH_ALL;
@@ -441,6 +605,9 @@ exec_query(int argc, char **argv)
			case 'f':
				pkgname = optarg;
				break;
+
			case 'e':
+
				condition = optarg;
+
				break;
			default:
				usage_query();
				return (EX_USAGE);
@@ -455,7 +622,7 @@ exec_query(int argc, char **argv)
		return (EX_USAGE);
	}

-
	if ((argc == 1) ^ (match == MATCH_ALL) && pkgname == NULL) {
+
	if ((argc == 1) ^ (match == MATCH_ALL) && pkgname == NULL && condition == NULL) {
		usage_query();
		return (EX_USAGE);
	}
@@ -473,6 +640,12 @@ exec_query(int argc, char **argv)
		return (EXIT_SUCCESS);
	}

+
	if (condition != NULL) {
+
		sqlcond = sbuf_new_auto();
+
		if (format_sql_condition(condition, sqlcond) != EPKG_OK)
+
			return (EX_USAGE);
+
	}
+

	ret = pkgdb_open(&db, PKGDB_DEFAULT);
	if (ret == EPKG_ENODB) {
		if (geteuid() == 0)
@@ -482,6 +655,22 @@ exec_query(int argc, char **argv)
		return (EXIT_SUCCESS);
	}

+
	if (condition != NULL) {
+
		sbuf_finish(sqlcond);
+
		if ((it = pkgdb_query_condition(db, sbuf_data(sqlcond))) == NULL)
+
			return (EX_IOERR);
+

+
		while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK)
+
			print_query(pkg, argv[0], multiline);
+

+
		pkgdb_it_free(it);
+

+
		if (ret != EPKG_END)
+
			return (EX_SOFTWARE);
+

+
		return (EXIT_SUCCESS);
+
	}
+

	if (match == MATCH_ALL) {
		if ((it = pkgdb_query(db, NULL, match)) == NULL)
			return (EX_IOERR);