Commit 9567337f authored by Timo Teräs's avatar Timo Teräs

fetch: new applet to download .apk files

Fixes #24.
parent a23f6f4a
...@@ -27,6 +27,7 @@ apk_OBJS = \ ...@@ -27,6 +27,7 @@ apk_OBJS = \
index.o \ index.o \
info.o \ info.o \
search.o \ search.o \
fetch.o \
audit.o \ audit.o \
apk.o apk.o
......
...@@ -20,8 +20,6 @@ typedef int (*apk_archive_entry_parser)(void *ctx, ...@@ -20,8 +20,6 @@ typedef int (*apk_archive_entry_parser)(void *ctx,
const struct apk_file_info *ae, const struct apk_file_info *ae,
struct apk_istream *istream); struct apk_istream *istream);
int apk_file_get_info(const char *filename, struct apk_file_info *fi);
int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx); int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx); int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx);
......
...@@ -111,6 +111,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, ...@@ -111,6 +111,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
#define APK_OPENF_READ 0x0000 #define APK_OPENF_READ 0x0000
#define APK_OPENF_WRITE 0x0001 #define APK_OPENF_WRITE 0x0001
#define APK_OPENF_CREATE 0x0002 #define APK_OPENF_CREATE 0x0002
#define APK_OPENF_EMPTY_STATE 0x0004
int apk_db_open(struct apk_database *db, const char *root, unsigned int flags); int apk_db_open(struct apk_database *db, const char *root, unsigned int flags);
int apk_db_write_config(struct apk_database *db); int apk_db_write_config(struct apk_database *db);
......
...@@ -58,6 +58,7 @@ extern unsigned int apk_flags; ...@@ -58,6 +58,7 @@ extern unsigned int apk_flags;
#define APK_CLEAN_PROTECTED 0x0004 #define APK_CLEAN_PROTECTED 0x0004
#define APK_PROGRESS 0x0008 #define APK_PROGRESS 0x0008
#define APK_UPGRADE 0x0010 #define APK_UPGRADE 0x0010
#define APK_RECURSIVE 0x0020
#define apk_error(args...) apk_log("ERROR: ", args); #define apk_error(args...) apk_log("ERROR: ", args);
#define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); } #define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); }
......
...@@ -67,4 +67,6 @@ struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode); ...@@ -67,4 +67,6 @@ struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode);
apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size); apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
apk_blob_t apk_blob_from_file(const char *file); apk_blob_t apk_blob_from_file(const char *file);
int apk_file_get_info(const char *filename, struct apk_file_info *fi);
#endif #endif
...@@ -14,7 +14,19 @@ ...@@ -14,7 +14,19 @@
#include "apk_database.h" #include "apk_database.h"
struct apk_state; typedef void *apk_name_state_t;
struct apk_change {
struct list_head change_list;
struct apk_package *oldpkg;
struct apk_package *newpkg;
};
struct apk_state {
int refs;
struct list_head change_list_head;
apk_name_state_t name[];
};
struct apk_state *apk_state_new(struct apk_database *db); struct apk_state *apk_state_new(struct apk_database *db);
struct apk_state *apk_state_dup(struct apk_state *state); struct apk_state *apk_state_dup(struct apk_state *state);
......
...@@ -693,18 +693,20 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) ...@@ -693,18 +693,20 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
apk_blob_for_each_segment(blob, ":", add_protected_path, db); apk_blob_for_each_segment(blob, ":", add_protected_path, db);
if (root != NULL) { if (root != NULL) {
r = apk_db_read_state(db); if (!(flags & APK_OPENF_EMPTY_STATE)) {
if (r == -ENOENT && (flags & APK_OPENF_CREATE)) { r = apk_db_read_state(db);
r = apk_db_create(db); if (r == -ENOENT && (flags & APK_OPENF_CREATE)) {
r = apk_db_create(db);
if (r != 0) {
msg = "Unable to create database";
goto ret_r;
}
r = apk_db_read_state(db);
}
if (r != 0) { if (r != 0) {
msg = "Unable to create database"; msg = "Unable to read database state";
goto ret_r; goto ret_r;
} }
r = apk_db_read_state(db);
}
if (r != 0) {
msg = "Unable to read database state";
goto ret_r;
} }
if (apk_repos == NULL) if (apk_repos == NULL)
......
/* fetch.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_state.h"
#include "apk_io.h"
#define FETCH_RECURSIVE 1
#define FETCH_STDOUT 2
struct fetch_ctx {
unsigned int flags;
const char *outdir;
};
static int fetch_parse(void *ctx, int optch, int optindex, const char *optarg)
{
struct fetch_ctx *fctx = (struct fetch_ctx *) ctx;
switch (optch) {
case 'R':
fctx->flags |= FETCH_RECURSIVE;
break;
case 's':
fctx->flags |= FETCH_STDOUT;
break;
case 'o':
fctx->outdir = optarg;
break;
default:
return -1;
}
return 0;
}
static int fetch_package(struct fetch_ctx *fctx,
struct apk_database *db,
struct apk_package *pkg)
{
struct apk_istream *is;
char file[256];
int i, r, fd;
if (fctx->flags & FETCH_STDOUT) {
fd = STDOUT_FILENO;
} else {
struct apk_file_info fi;
snprintf(file, sizeof(file), "%s/%s-%s.apk",
fctx->outdir ? fctx->outdir : ".",
pkg->name->name, pkg->version);
if (apk_file_get_info(file, &fi) == 0 &&
fi.size == pkg->size)
return 0;
fd = creat(file, 0644);
if (fd < 0) {
apk_error("Unable to create '%s'", file);
return -1;
}
}
apk_message("Downloading %s-%s", pkg->name->name, pkg->version);
for (i = 0; i < APK_MAX_REPOS; i++)
if (pkg->repos & BIT(i))
break;
if (i >= APK_MAX_REPOS) {
apk_error("%s-%s: not present in any repository",
pkg->name->name, pkg->version);
return -1;
}
snprintf(file, sizeof(file), "%s/%s-%s.apk",
db->repos[i].url, pkg->name->name, pkg->version);
is = apk_istream_from_url(file);
if (is == NULL) {
apk_error("Unable to download '%s'", file);
return -1;
}
r = apk_istream_splice(is, fd, pkg->size, NULL, NULL);
if (r != pkg->size) {
is->close(is);
apk_error("Unable to download '%s'", file);
return -1;
}
return 0;
}
static int fetch_main(void *ctx, int argc, char **argv)
{
struct fetch_ctx *fctx = (struct fetch_ctx *) ctx;
struct apk_database db;
int i, j, r;
r = apk_db_open(&db, apk_root, APK_OPENF_EMPTY_STATE);
if (r != 0)
return r;
for (i = 0; i < argc; i++) {
struct apk_dependency dep = (struct apk_dependency) {
.name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])),
.result_mask = APK_DEPMASK_REQUIRE,
};
if (fctx->flags & FETCH_RECURSIVE) {
struct apk_state *state;
struct apk_change *change;
state = apk_state_new(&db);
r = apk_state_lock_dependency(state, &dep);
if (r != 0) {
apk_state_unref(state);
apk_error("Unable to install '%s'",
dep.name->name);
goto err;
}
list_for_each_entry(change, &state->change_list_head, change_list) {
r = fetch_package(fctx, &db, change->newpkg);
if (r != 0)
goto err;
}
apk_state_unref(state);
} else if (dep.name->pkgs != NULL) {
struct apk_package *pkg = NULL;
for (j = 0; j < dep.name->pkgs->num; j++)
if (pkg == NULL ||
apk_version_compare(APK_BLOB_STR(dep.name->pkgs->item[j]->version),
APK_BLOB_STR(pkg->version))
== APK_VERSION_GREATER)
pkg = dep.name->pkgs->item[j];
r = fetch_package(fctx, &db, pkg);
if (r != 0)
goto err;
} else {
apk_message("Unable to get '%s'", dep.name->name);
r = -1;
break;
}
}
err:
apk_db_close(&db);
return r;
}
static struct option fetch_options[] = {
{ "recursive", no_argument, NULL, 'R' },
{ "stdout", no_argument, NULL, 's' },
{ "output", required_argument, NULL, 'o' },
};
static struct apk_applet apk_fetch = {
.name = "fetch",
.usage = "[-R|--recursive|--stdout] [-o dir] apkname...",
.context_size = sizeof(struct fetch_ctx),
.num_options = ARRAY_SIZE(fetch_options),
.options = fetch_options,
.parse = fetch_parse,
.main = fetch_main,
};
APK_DEFINE_APPLET(apk_fetch);
...@@ -16,25 +16,11 @@ ...@@ -16,25 +16,11 @@
#include "apk_state.h" #include "apk_state.h"
#include "apk_database.h" #include "apk_database.h"
typedef void *apk_name_state_t;
struct apk_change {
struct list_head change_list;
struct apk_package *oldpkg;
struct apk_package *newpkg;
};
struct apk_name_choices { struct apk_name_choices {
unsigned short refs, num; unsigned short refs, num;
struct apk_package *pkgs[]; struct apk_package *pkgs[];
}; };
struct apk_state {
int refs;
struct list_head change_list_head;
apk_name_state_t name[];
};
#if 0 #if 0
struct apk_deferred_state { struct apk_deferred_state {
unsigned int preference; unsigned int preference;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment