From: Michael Schroeder Date: Thu, 4 Apr 2019 14:23:39 +0000 (+0200) Subject: Add repo_add_conda() and conda2solv X-Git-Tag: 0.7.5~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66fa37ec353e2373d3dd63d7b75472e9a4145729;p=thirdparty%2Flibsolv.git Add repo_add_conda() and conda2solv --- diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 6dd28b1a..d0444035 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -116,6 +116,13 @@ IF (ENABLE_APPDATA) repo_appdata.h) ENDIF (ENABLE_APPDATA) +IF (ENABLE_CONDA) + SET (libsolvext_SRCS ${libsolvext_SRCS} + repo_conda.c) + SET (libsolvext_HEADERS ${libsolvext_HEADERS} + repo_conda.h) +ENDIF (ENABLE_CONDA) + IF (ENABLE_RPMMD OR ENABLE_SUSEREPO) SET (libsolvext_SRCS ${libsolvext_SRCS} repodata_diskusage.c) @@ -126,6 +133,11 @@ IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_ solv_xmlparser.c) ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) +IF (ENABLE_CONDA) + SET (libsolvext_SRCS ${libsolvext_SRCS} + solv_jsonparser.c) +ENDIF (ENABLE_CONDA) + IF (ENABLE_ZCHUNK_COMPRESSION) SET (libsolvext_SRCS ${libsolvext_SRCS} solv_zchunk.c) diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 4896e855..ef028f0f 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -10,6 +10,7 @@ SOLV_1.0 { repo_add_arch_repo; repo_add_autopattern; repo_add_code11_products; + repo_add_conda; repo_add_content; repo_add_comps; repo_add_cudf; diff --git a/ext/repo_conda.c b/ext/repo_conda.c new file mode 100644 index 00000000..4f76c8f7 --- /dev/null +++ b/ext/repo_conda.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2019, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "solv_jsonparser.h" +#include "conda.h" +#include "repo_conda.h" + +struct parsedata { + Pool *pool; + Repo *repo; + Repodata *data; +}; + +static int +parse_deps(struct parsedata *pd, struct solv_jsonparser *jp, Offset *depp) +{ + int type = JP_ARRAY; + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END) + { + if (type == JP_STRING) + { + Id id = pool_conda_matchspec(pd->pool, jp->value); + if (id) + *depp = repo_addid_dep(pd->repo, *depp, id, 0); + } + else + type = jsonparser_skip(jp, type); + } + return type; +} + +static int +parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn) +{ + int type = JP_OBJECT; + Pool *pool= pd->pool; + Repodata *data = pd->data; + Solvable *s; + Id handle = repo_add_solvable(pd->repo); + s = pool_id2solvable(pool, handle); + char *fn = 0; + char *subdir = 0; + + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END) + { + if (type == JP_STRING && !strcmp(jp->key, "build")) + repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, jp->value); + else if (type == JP_STRING && !strcmp(jp->key, "build_number")) + repodata_set_str(data, handle, SOLVABLE_BUILDVERSION, jp->value); + else if (type == JP_ARRAY && !strcmp(jp->key, "depends")) + type = parse_deps(pd, jp, &s->requires); + else if (type == JP_ARRAY && !strcmp(jp->key, "requires")) + type = parse_deps(pd, jp, &s->requires); + else if (type == JP_STRING && !strcmp(jp->key, "license")) + repodata_add_poolstr_array(data, handle, SOLVABLE_LICENSE, jp->value); + else if (type == JP_STRING && !strcmp(jp->key, "md5")) + repodata_set_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, jp->value); + else if (type == JP_STRING && !strcmp(jp->key, "sha256")) + repodata_set_checksum(data, handle, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, jp->value); + else if (type == JP_STRING && !strcmp(jp->key, "name")) + s->name = pool_str2id(pool, jp->value, 1); + else if (type == JP_STRING && !strcmp(jp->key, "version")) + s->evr= pool_str2id(pool, jp->value, 1); + else if (type == JP_STRING && !strcmp(jp->key, "fn") && !fn) + fn = solv_strdup(jp->value); + else if (type == JP_STRING && !strcmp(jp->key, "subdir") && !subdir) + subdir = solv_strdup(jp->value); + else if (type == JP_NUMBER && !strcmp(jp->key, "size")) + repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(jp->value, 0, 10)); + else if (type == JP_NUMBER && !strcmp(jp->key, "timestamp")) + { + unsigned long long ts = strtoull(jp->value, 0, 10); + if (ts > 253402300799ULL) + ts /= 1000; + repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts); + } + else + type = jsonparser_skip(jp, type); + } + if (fn || kfn) + repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn); + solv_free(fn); + solv_free(subdir); + if (!s->evr) + s->evr = 1; + if (s->name) + s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); + return type; +} + +static int +parse_packages(struct parsedata *pd, struct solv_jsonparser *jp) +{ + int type = JP_OBJECT; + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END) + { + if (type == JP_OBJECT) + { + char *fn = solv_strdup(jp->key); + type = parse_package(pd, jp, fn); + solv_free(fn); + } + else + type = jsonparser_skip(jp, type); + } + return type; +} + +static int +parse_packages2(struct parsedata *pd, struct solv_jsonparser *jp) +{ + int type = JP_ARRAY; + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END) + { + if (type == JP_OBJECT) + type = parse_package(pd, jp, 0); + else + type = jsonparser_skip(jp, type); + } + return type; +} + +static int +parse_main(struct parsedata *pd, struct solv_jsonparser *jp) +{ + int type = JP_OBJECT; + while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END) + { + if (type == JP_OBJECT && !strcmp("packages", jp->key)) + type = parse_packages(pd, jp); + if (type == JP_ARRAY && !strcmp("packages", jp->key)) + type = parse_packages2(pd, jp); + else + type = jsonparser_skip(jp, type); + } + return type; +} + +int +repo_add_conda(Repo *repo, FILE *fp, int flags) +{ + Pool *pool = repo->pool; + struct solv_jsonparser jp; + struct parsedata pd; + Repodata *data; + int type, ret = 0; + + data = repo_add_repodata(repo, flags); + + memset(&pd, 0, sizeof(pd)); + pd.pool = pool; + pd.repo = repo; + pd.data = data; + + jsonparser_init(&jp, fp); + if ((type = jsonparser_parse(&jp)) != JP_OBJECT) + ret = pool_error(pool, -1, "repository does not start with an object"); + else if ((type = parse_main(&pd, &jp)) != JP_OBJECT_END) + ret = pool_error(pool, -1, "parse error line %d", jp.line); + jsonparser_free(&jp); + + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + + return ret; +} + diff --git a/ext/repo_conda.h b/ext/repo_conda.h new file mode 100644 index 00000000..7e90a3d0 --- /dev/null +++ b/ext/repo_conda.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2019, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +extern int repo_add_conda(Repo *repo, FILE *fp, int flags); diff --git a/ext/solv_jsonparser.c b/ext/solv_jsonparser.c index 053ee6f4..ae044e63 100644 --- a/ext/solv_jsonparser.c +++ b/ext/solv_jsonparser.c @@ -15,7 +15,7 @@ #include "util.h" #include "solv_jsonparser.h" -struct solv_jsonparser * +void jsonparser_init(struct solv_jsonparser *jp, FILE *fp) { memset(jp, 0, sizeof(*jp)); @@ -24,7 +24,6 @@ jsonparser_init(struct solv_jsonparser *jp, FILE *fp) jp->line = jp->nextline = 1; jp->nextc = ' '; queue_init(&jp->stateq); - return jp; } struct solv_jsonparser * diff --git a/ext/solv_jsonparser.h b/ext/solv_jsonparser.h index d58d9e3a..e0274f9c 100644 --- a/ext/solv_jsonparser.h +++ b/ext/solv_jsonparser.h @@ -41,7 +41,7 @@ struct solv_jsonparser { #define JP_ARRAY 8 #define JP_ARRAY_END 9 -struct solv_jsonparser *jsonparser_init(struct solv_jsonparser *jp, FILE *fp); +void jsonparser_init(struct solv_jsonparser *jp, FILE *fp); struct solv_jsonparser *jsonparser_free(struct solv_jsonparser *jp); int jsonparser_parse(struct solv_jsonparser *jp); int jsonparser_skip(struct solv_jsonparser *jp, int type); diff --git a/src/libsolv.ver b/src/libsolv.ver index d983b541..eafe3e68 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -449,4 +449,5 @@ SOLV_1.2 { SOLV_1.3 { repodata_set_kv; solv_setcloexec; + pool_conda_matchspec; } SOLV_1.2; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 0d677f69..e2aa4f1a 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -98,6 +98,13 @@ TARGET_LINK_LIBRARIES (appdata2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRAR SET (tools_list ${tools_list} appdata2solv) ENDIF (ENABLE_APPDATA) +IF (ENABLE_CONDA) +ADD_EXECUTABLE (conda2solv conda2solv.c) +TARGET_LINK_LIBRARIES (conda2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) + +SET (tools_list ${tools_list} conda2solv) +ENDIF (ENABLE_CONDA) + ADD_EXECUTABLE (dumpsolv dumpsolv.c ) TARGET_LINK_LIBRARIES (dumpsolv libsolv) diff --git a/tools/conda2solv.c b/tools/conda2solv.c new file mode 100644 index 00000000..2b8f3c4e --- /dev/null +++ b/tools/conda2solv.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * conda2solv.c + * + * parse a conda repository file + * + * reads from stdin + * writes to stdout + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_conda.h" +#include "solv_xfopen.h" +#include "common_write.h" + + +static void +usage(int status) +{ + fprintf(stderr, "\nUsage:\n" + "conda2solv\n" + " reads a 'synthesis' repository from and writes a .solv file to \n" + " -h : print help & exit\n" + ); + exit(status); +} + +int +main(int argc, char **argv) +{ + Pool *pool; + Repo *repo; + int c; + + while ((c = getopt(argc, argv, "h")) >= 0) + { + switch(c) + { + case 'h': + usage(0); + break; + default: + usage(1); + break; + } + } + pool = pool_create(); + repo = repo_create(pool, ""); + if (repo_add_conda(repo, stdin, 0)) + { + fprintf(stderr, "conda2solv: %s\n", pool_errstr(pool)); + exit(1); + } + repo_internalize(repo); + tool_write(repo, stdout); + pool_free(pool); + exit(0); +}