Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Initial commit of the "pkg fetch" command
Marin Atanasov Nikolov committed 14 years ago
commit a29d6cd1999a4b15eb7082bdbf7e457834616fab
parent 5141e61cd83cb29918ebe0d014d16a20da3cf7fd
6 files changed +275 -2
modified libpkg/pkg.h
@@ -222,7 +222,8 @@ typedef enum _pkg_script_t {
typedef enum _pkg_jobs_t {
	PKG_JOBS_INSTALL,
	PKG_JOBS_DEINSTALL,
-
	PKG_JOBS_UPGRADE
+
	PKG_JOBS_UPGRADE,
+
	PKG_JOBS_FETCH
} pkg_jobs_t;

typedef enum _pkg_config_key {
@@ -651,6 +652,7 @@ struct pkgdb_it *pkgdb_query_upgrades(struct pkgdb *db, const char *reponame, bo
struct pkgdb_it *pkgdb_query_downgrades(struct pkgdb *db, const char *reponame);
struct pkgdb_it *pkgdb_query_delete(struct pkgdb *db, match_t type, int nbpkgs, char **pkgs, int recursive);
struct pkgdb_it *pkgdb_query_autoremove(struct pkgdb *db);
+
struct pkgdb_it *pkgdb_query_fetch(struct pkgdb *db, match_t type, int nbpkgs, char **pkgs, const char *reponame);

/**
 * @todo Return directly the struct pkg?
modified libpkg/pkgdb.c
@@ -2971,3 +2971,136 @@ pkgdb_set2(struct pkgdb *db, struct pkg *pkg, ...)

	return (ret);
}
+

+
struct pkgdb_it *
+
pkgdb_query_fetch(struct pkgdb *db, match_t match, int nbpkgs, char **pkgs, const char *repo)
+
{
+
	sqlite3_stmt *stmt = NULL;
+
	int i = 0;
+
	struct sbuf *sql = sbuf_new_auto();
+
	const char *how = NULL;
+
	const char *reponame = NULL;
+
	bool multirepos_enabled = false;
+

+
	const char finalsql[] = "SELECT pkgid AS id, origin, name, version, "
+
		"flatsize, newversion, newflatsize, pkgsize, cksum, repopath, "
+
		"'%s' AS dbname FROM pkgjobs ORDER BY weight DESC;";
+
	
+
	const char main_sql[] = "INSERT OR IGNORE INTO pkgjobs (pkgid, origin, name, version, "
+
			"flatsize, pkgsize, cksum, repopath) "
+
			"SELECT id, origin, name, version, flatsize, pkgsize, "
+
			"cksum, path FROM '%s'.packages WHERE ";
+

+
	const char deps_sql[] = "INSERT OR IGNORE INTO pkgjobs (pkgid, origin, name, version, "
+
				"flatsize, pkgsize, cksum, repopath) "
+
				"SELECT DISTINCT r.id, r.origin, r.name, r.version, "
+
				"r.flatsize, r.pkgsize, r.cksum, r.path "
+
				"FROM '%s'.packages AS r where r.origin IN "
+
				"(SELECT d.origin FROM '%s'.deps AS d, pkgjobs AS j WHERE d.package_id = j.pkgid) "
+
				"AND (SELECT origin FROM main.packages WHERE origin=r.origin AND version=r.version) IS NULL;";
+

+
	const char weight_sql[] = "UPDATE pkgjobs SET weight=(SELECT count(*) FROM '%s'.deps AS d WHERE d.origin=pkgjobs.origin)";
+

+
	assert(db != NULL);
+

+
	if (db->type != PKGDB_REMOTE) {
+
		pkg_emit_error("remote database not attached (misuse)");
+
		return (NULL);
+
	}
+

+
	/* Working on multiple repositories */
+
	pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multirepos_enabled);
+

+
	if (multirepos_enabled) {
+
		if (repo != NULL) {
+
			if (!is_attached(db->sqlite, repo)) {
+
				pkg_emit_error("repository '%s' does not exists", repo);
+
				return (NULL);
+
			}
+

+
			reponame = repo;
+
		} else {
+
			/* default repository in multi-repos is 'default' */
+
			reponame = "default";
+
		}
+
	} else {
+
		/* default repository in single-repo is 'remote' */
+
		reponame = "remote";
+
	}
+

+
	sbuf_printf(sql, main_sql, reponame);
+

+
	switch (match) {
+
		case MATCH_ALL:
+
			how = NULL;
+
			break;
+
		case MATCH_EXACT:
+
			how = "%s = ?1";
+
			break;
+
		case MATCH_GLOB:
+
			how = "%s GLOB ?1";
+
			break;
+
		case MATCH_REGEX:
+
			how = "%s REGEXP ?1";
+
			break;
+
		case MATCH_EREGEX:
+
			how = "EREGEXP(?1, %s)";
+
			break;
+
	}
+

+
	create_temporary_pkgjobs(db->sqlite);
+

+
	sbuf_printf(sql, how, "name");
+
	sbuf_cat(sql, " OR ");
+
	sbuf_printf(sql, how, "origin");
+
	sbuf_cat(sql, " OR ");
+
	sbuf_printf(sql, how, "name || \"-\" || version");
+
	sbuf_finish(sql);
+

+
	for (i = 0; i < nbpkgs; i++) {
+
		if (sqlite3_prepare_v2(db->sqlite, sbuf_get(sql), -1, &stmt, NULL) != SQLITE_OK) {
+
			ERROR_SQLITE(db->sqlite);
+
			return (NULL);
+
		}
+
		sqlite3_bind_text(stmt, 1, pkgs[i], -1, SQLITE_STATIC);
+
		while (sqlite3_step(stmt) != SQLITE_DONE);
+

+
		/* report if package was not found in the database */
+
		if (sqlite3_changes(db->sqlite) == 0)
+
			pkg_emit_error("Package '%s' was not found in the repositories", pkgs[i]);
+
	}
+

+
	sqlite3_finalize(stmt);
+
	sbuf_clear(sql);
+

+
	/* Append dependencies */
+
	sbuf_reset(sql);
+
	sbuf_printf(sql, deps_sql, reponame, reponame);
+
	sbuf_finish(sql);
+

+
	do {
+
		sql_exec(db->sqlite, sbuf_get(sql));
+
	} while (sqlite3_changes(db->sqlite) != 0);
+

+
	sbuf_reset(sql);
+
	sbuf_printf(sql, weight_sql, reponame);
+
	sbuf_finish(sql);
+

+
	/* Set weight */
+
	sql_exec(db->sqlite, sbuf_get(sql));
+

+
	/* Execute final SQL */
+
	sbuf_reset(sql);
+
	sbuf_printf(sql, finalsql, reponame);
+
	sbuf_finish(sql);
+

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

+
	sbuf_finish(sql);
+
	sbuf_delete(sql);
+

+
	return (pkgdb_it_new(db, stmt, PKG_REMOTE));
+
}
modified pkg/Makefile
@@ -23,7 +23,8 @@ SRCS= add.c \
		updating.c \
		utils.c \
		version.c \
-
		which.c
+
		which.c \
+
		fetch.c
PREFIX?=	/usr/local
BINDIR=		${PREFIX}/sbin
MANDIR=		${PREFIX}/man/man
added pkg/fetch.c
@@ -0,0 +1,132 @@
+
/*
+
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
+
 * 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 <sys/types.h>
+

+
#include <err.h>
+
#include <libgen.h>
+
#include <stdbool.h>
+
#include <stdio.h>
+
#include <string.h>
+
#include <sysexits.h>
+
#include <unistd.h>
+
#include <libutil.h>
+

+
#include <pkg.h>
+

+
#include "pkgcli.h"
+

+
void
+
usage_fetch(void)
+
{
+
	fprintf(stderr, "usage: pkg fetch [-r reponame] [-yqgxX] <pkg-name> <...>\n\n");
+
	fprintf(stderr, "For more information see 'pkg help fetch'.\n");
+
}
+

+
int
+
exec_fetch(int argc, char **argv)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkgdb_it *it = NULL;
+
	struct pkgdb *db = NULL;
+
	struct pkg_jobs *jobs = NULL;
+
	const char *reponame = NULL;
+
	int retcode = EXIT_FAILURE;
+
	int ch;
+
	bool yes = false;
+
	match_t match = MATCH_EXACT;
+

+
	while ((ch = getopt(argc, argv, "ygxXr:q")) != -1) {
+
		switch (ch) {
+
		case 'y':
+
			yes = true;
+
			break;
+
		case 'g':
+
			match = MATCH_GLOB;
+
			break;
+
		case 'x':
+
			match = MATCH_REGEX;
+
			break;
+
		case 'X':
+
			match = MATCH_EREGEX;
+
			break;
+
		case 'r':
+
			reponame = optarg;
+
			break;
+
		case 'q':
+
			quiet = true;
+
			break;
+
		default:
+
			usage_fetch();
+
			return (EX_USAGE);
+
		}
+
	}
+
	argc -= optind;
+
	argv += optind;
+
	
+
	if (argc < 1) {
+
		usage_fetch();
+
		return (EX_USAGE);
+
	}
+

+
	if (geteuid() != 0) {
+
		warnx("fetching packages can only be done as root");
+
		return (EX_NOPERM);
+
	}
+

+
	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) {
+
		return (EX_IOERR);
+
	}
+

+
	if (pkg_jobs_new(&jobs, PKG_JOBS_FETCH, db) != EPKG_OK) {
+
		goto cleanup;
+
	}
+

+
	if ((it = pkgdb_query_fetch(db, match, argc, argv, reponame)) == NULL)
+
		goto cleanup;
+

+
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_DEPS) == EPKG_OK) {
+
		pkg_jobs_add(jobs, pkg);
+
		pkg = NULL;
+
	}
+
	
+
	pkgdb_it_free(it);
+

+
	if (pkg_jobs_is_empty(jobs))
+
		goto cleanup;
+

+
	if (yes)
+
		if (pkg_jobs_apply(jobs, 0) != EPKG_OK)
+
			goto cleanup;
+

+
	retcode = EXIT_SUCCESS;
+

+
	cleanup:
+
	pkg_jobs_free(jobs);
+
	pkgdb_close(db);
+

+
	return (retcode);
+
}
modified pkg/main.c
@@ -81,6 +81,7 @@ static struct commands {
	{ "upgrade", "Performs upgrades of package software distributions", exec_upgrade, usage_upgrade},
	{ "version", "Summarize installed versions of packages", exec_version, usage_version},
	{ "which", "Displays which package installed a specific file", exec_which, usage_which},
+
	{ "fetch", "Fetches packages from a remote repository", exec_fetch, usage_fetch},
};

const unsigned int cmd_len = (sizeof(cmd)/sizeof(cmd[0]));
modified pkg/pkgcli.h
@@ -107,6 +107,10 @@ void usage_updating(void);
int exec_upgrade(int, char **);
void usage_upgrade(void);

+
/* pkg fetch */
+
int exec_fetch(int, char **);
+
void usage_fetch(void);
+

/* pkg version */
#define VERSION_INDEX (1<<0)
#define VERSION_ORIGIN (1<<1)