0828aff6b3b56cd498f86d344448b391b91315e2
[platform/upstream/libsolv.git] / ext / repo_conda.c
1 /*
2  * Copyright (c) 2019, SUSE LLC.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #define _GNU_SOURCE
9 #include <sys/types.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "pool.h"
15 #include "repo.h"
16 #include "chksum.h"
17 #include "solv_jsonparser.h"
18 #include "conda.h"
19 #include "repo_conda.h"
20
21 struct parsedata {
22   Pool *pool;
23   Repo *repo;
24   Repodata *data;
25 };
26
27 static int
28 parse_deps(struct parsedata *pd, struct solv_jsonparser *jp, Offset *depp)
29 {
30   int type = JP_ARRAY;
31   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
32     {
33       if (type == JP_STRING)
34         {
35           Id id = pool_conda_matchspec(pd->pool, jp->value);
36           if (id)
37             *depp = repo_addid_dep(pd->repo, *depp, id, 0);
38         }
39       else
40         type = jsonparser_skip(jp, type);
41     }
42   return type;
43 }
44
45 static int
46 parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn)
47 {
48   int type = JP_OBJECT;
49   Pool *pool= pd->pool;
50   Repodata *data = pd->data;
51   Solvable *s;
52   Id handle = repo_add_solvable(pd->repo);
53   s = pool_id2solvable(pool, handle);
54   char *fn = 0;
55   char *subdir = 0;
56
57   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
58     {
59       if (type == JP_STRING && !strcmp(jp->key, "build"))
60         repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, jp->value);
61       else if (type == JP_NUMBER && !strcmp(jp->key, "build_number"))
62         repodata_set_str(data, handle, SOLVABLE_BUILDVERSION, jp->value);
63       else if (type == JP_ARRAY && !strcmp(jp->key, "depends"))
64         type = parse_deps(pd, jp, &s->requires);
65       else if (type == JP_ARRAY && !strcmp(jp->key, "requires"))
66         type = parse_deps(pd, jp, &s->requires);
67       else if (type == JP_STRING && !strcmp(jp->key, "license"))
68         repodata_add_poolstr_array(data, handle, SOLVABLE_LICENSE, jp->value);
69       else if (type == JP_STRING && !strcmp(jp->key, "md5"))
70         repodata_set_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, jp->value);
71       else if (type == JP_STRING && !strcmp(jp->key, "sha256"))
72         repodata_set_checksum(data, handle, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, jp->value);
73       else if (type == JP_STRING && !strcmp(jp->key, "name"))
74         s->name = pool_str2id(pool, jp->value, 1);
75       else if (type == JP_STRING && !strcmp(jp->key, "version"))
76         s->evr= pool_str2id(pool, jp->value, 1);
77       else if (type == JP_STRING && !strcmp(jp->key, "fn") && !fn)
78         fn = solv_strdup(jp->value);
79       else if (type == JP_STRING && !strcmp(jp->key, "subdir") && !subdir)
80         subdir = solv_strdup(jp->value);
81       else if (type == JP_NUMBER && !strcmp(jp->key, "size"))
82         repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(jp->value, 0, 10));
83       else if (type == JP_NUMBER && !strcmp(jp->key, "timestamp"))
84         {
85           unsigned long long ts = strtoull(jp->value, 0, 10);
86           if (ts > 253402300799ULL)
87             ts /= 1000;
88           repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts);
89         }
90       else
91         type = jsonparser_skip(jp, type);
92     }
93   if (fn || kfn)
94     repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
95   solv_free(fn);
96   solv_free(subdir);
97   if (!s->evr)
98     s->evr = 1;
99   if (s->name)
100     s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
101   return type;
102 }
103
104 static int
105 parse_packages(struct parsedata *pd, struct solv_jsonparser *jp)
106 {
107   int type = JP_OBJECT;
108   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
109     {
110       if (type == JP_OBJECT)
111         {
112           char *fn = solv_strdup(jp->key);
113           type = parse_package(pd, jp, fn);
114           solv_free(fn);
115         }
116       else
117         type = jsonparser_skip(jp, type);
118     }
119   return type;
120 }
121
122 static int
123 parse_packages2(struct parsedata *pd, struct solv_jsonparser *jp)
124 {
125   int type = JP_ARRAY;
126   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
127     {
128       if (type == JP_OBJECT)
129         type = parse_package(pd, jp, 0);
130       else
131         type = jsonparser_skip(jp, type);
132     }
133   return type;
134 }
135
136 static int
137 parse_main(struct parsedata *pd, struct solv_jsonparser *jp)
138 {
139   int type = JP_OBJECT;
140   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
141     {
142       if (type == JP_OBJECT && !strcmp("packages", jp->key))
143         type = parse_packages(pd, jp);
144       if (type == JP_ARRAY && !strcmp("packages", jp->key))
145         type = parse_packages2(pd, jp);
146       else
147         type = jsonparser_skip(jp, type);
148     }
149   return type;
150 }
151
152 int
153 repo_add_conda(Repo *repo, FILE *fp, int flags)
154 {
155   Pool *pool = repo->pool;
156   struct solv_jsonparser jp;
157   struct parsedata pd;
158   Repodata *data;
159   int type, ret = 0;
160
161   data = repo_add_repodata(repo, flags);
162
163   memset(&pd, 0, sizeof(pd));
164   pd.pool = pool;
165   pd.repo = repo;
166   pd.data = data;
167
168   jsonparser_init(&jp, fp);
169   if ((type = jsonparser_parse(&jp)) != JP_OBJECT)
170     ret = pool_error(pool, -1, "repository does not start with an object");
171   else if ((type = parse_main(&pd, &jp)) != JP_OBJECT_END)
172     ret = pool_error(pool, -1, "parse error line %d", jp.line);
173   jsonparser_free(&jp);
174
175   if (!(flags & REPO_NO_INTERNALIZE))
176     repodata_internalize(data);
177
178   return ret;
179 }
180