summaryrefslogtreecommitdiff
path: root/src/fetch.c
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 /src/fetch.c
parenta23f6f4afb0f819c6c478975df41e235e8d0953a (diff)
downloadapk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.gz
apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.bz2
apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.tar.xz
apk-tools-9567337fd2444aa9b30a6cbfdd5bc9a98d171f25.zip
fetch: new applet to download .apk files
Fixes #24.
Diffstat (limited to 'src/fetch.c')
-rw-r--r--src/fetch.c185
1 files changed, 185 insertions, 0 deletions
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);
+