summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-04-15 09:56:09 +0300
committerTimo Teras <timo.teras@iki.fi>2009-04-15 09:56:09 +0300
commit9567337fd2444aa9b30a6cbfdd5bc9a98d171f25 (patch)
tree7811255a8e028774b154d67245283022092312b9
parenta23f6f4afb0f819c6c478975df41e235e8d0953a (diff)
fetch: new applet to download .apk files
Fixes #24.
-rw-r--r--src/Makefile1
-rw-r--r--src/apk_archive.h2
-rw-r--r--src/apk_database.h1
-rw-r--r--src/apk_defines.h1
-rw-r--r--src/apk_io.h2
-rw-r--r--src/apk_state.h14
-rw-r--r--src/database.c20
-rw-r--r--src/fetch.c185
-rw-r--r--src/state.c14
9 files changed, 214 insertions, 26 deletions
diff --git a/src/Makefile b/src/Makefile
index b9414ae..d4a7244 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -27,6 +27,7 @@ apk_OBJS = \
index.o \
info.o \
search.o \
+ fetch.o \
audit.o \
apk.o
diff --git a/src/apk_archive.h b/src/apk_archive.h
index b048398..4651255 100644
--- a/src/apk_archive.h
+++ b/src/apk_archive.h
@@ -20,8 +20,6 @@ typedef int (*apk_archive_entry_parser)(void *ctx,
const struct apk_file_info *ae,
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_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx);
diff --git a/src/apk_database.h b/src/apk_database.h
index b7d0eed..6ca630b 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -111,6 +111,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
#define APK_OPENF_READ 0x0000
#define APK_OPENF_WRITE 0x0001
#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_write_config(struct apk_database *db);
diff --git a/src/apk_defines.h b/src/apk_defines.h
index e8029de..ecb80d0 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -58,6 +58,7 @@ extern unsigned int apk_flags;
#define APK_CLEAN_PROTECTED 0x0004
#define APK_PROGRESS 0x0008
#define APK_UPGRADE 0x0010
+#define APK_RECURSIVE 0x0020
#define apk_error(args...) apk_log("ERROR: ", args);
#define apk_warning(args...) if (apk_verbosity > 0) { apk_log("WARNING: ", args); }
diff --git a/src/apk_io.h b/src/apk_io.h
index 8ee80f8..a903277 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -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_file(const char *file);
+int apk_file_get_info(const char *filename, struct apk_file_info *fi);
+
#endif
diff --git a/src/apk_state.h b/src/apk_state.h
index d065411..402b919 100644
--- a/src/apk_state.h
+++ b/src/apk_state.h
@@ -14,7 +14,19 @@
#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_dup(struct apk_state *state);
diff --git a/src/database.c b/src/database.c
index 9bf34ba..7162ef7 100644
--- a/src/database.c
+++ b/src/database.c
@@ -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);
if (root != NULL) {
- r = apk_db_read_state(db);
- if (r == -ENOENT && (flags & APK_OPENF_CREATE)) {
- r = apk_db_create(db);
+ if (!(flags & APK_OPENF_EMPTY_STATE)) {
+ r = apk_db_read_state(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) {
- msg = "Unable to create database";
+ msg = "Unable to read database state";
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)
diff --git a/src/fetch.c b/src/fetch.c
new file mode 100644
index 0000000..40b8a24
--- /dev/null
+++ b/src/fetch.c
@@ -0,0 +1,185 @@
+/* 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);
+
diff --git a/src/state.c b/src/state.c
index a0abb57..79655a9 100644
--- a/src/state.c
+++ b/src/state.c
@@ -16,25 +16,11 @@
#include "apk_state.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 {
unsigned short refs, num;
struct apk_package *pkgs[];
};
-struct apk_state {
- int refs;
- struct list_head change_list_head;
- apk_name_state_t name[];
-};
-
#if 0
struct apk_deferred_state {
unsigned int preference;