Imported Upstream version 0.7.11
[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_otherdeps(struct parsedata *pd, struct solv_jsonparser *jp, Id handle, Id keyname)
47 {
48   int type = JP_ARRAY;
49   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
50     {
51       if (type == JP_STRING)
52         {
53           Id id = pool_conda_matchspec(pd->pool, jp->value);
54           if (id)
55             repodata_add_idarray(pd->data, handle, keyname, id);
56         }
57       else
58         type = jsonparser_skip(jp, type);
59     }
60   return type;
61 }
62
63 static int
64 parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn)
65 {
66   int type = JP_OBJECT;
67   Pool *pool= pd->pool;
68   Repodata *data = pd->data;
69   Solvable *s;
70   Id handle = repo_add_solvable(pd->repo);
71   s = pool_id2solvable(pool, handle);
72   char *fn = 0;
73   char *subdir = 0;
74
75   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
76     {
77       if (type == JP_STRING && !strcmp(jp->key, "build"))
78         repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, jp->value);
79       else if (type == JP_NUMBER && !strcmp(jp->key, "build_number"))
80         repodata_set_str(data, handle, SOLVABLE_BUILDVERSION, jp->value);
81       else if (type == JP_ARRAY && !strcmp(jp->key, "depends"))
82         type = parse_deps(pd, jp, &s->requires);
83       else if (type == JP_ARRAY && !strcmp(jp->key, "requires"))
84         type = parse_deps(pd, jp, &s->requires);
85       else if (type == JP_ARRAY && !strcmp(jp->key, "constrains"))
86         type = parse_otherdeps(pd, jp, handle, SOLVABLE_CONSTRAINS);
87       else if (type == JP_STRING && !strcmp(jp->key, "license"))
88         repodata_add_poolstr_array(data, handle, SOLVABLE_LICENSE, jp->value);
89       else if (type == JP_STRING && !strcmp(jp->key, "md5"))
90         repodata_set_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, jp->value);
91       else if (type == JP_STRING && !strcmp(jp->key, "sha256"))
92         repodata_set_checksum(data, handle, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, jp->value);
93       else if (type == JP_STRING && !strcmp(jp->key, "name"))
94         s->name = pool_str2id(pool, jp->value, 1);
95       else if (type == JP_STRING && !strcmp(jp->key, "version"))
96         s->evr= pool_str2id(pool, jp->value, 1);
97       else if (type == JP_STRING && !strcmp(jp->key, "fn") && !fn)
98         fn = solv_strdup(jp->value);
99       else if (type == JP_STRING && !strcmp(jp->key, "subdir") && !subdir)
100         subdir = solv_strdup(jp->value);
101       else if (type == JP_NUMBER && !strcmp(jp->key, "size"))
102         repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(jp->value, 0, 10));
103       else if (type == JP_NUMBER && !strcmp(jp->key, "timestamp"))
104         {
105           unsigned long long ts = strtoull(jp->value, 0, 10);
106           if (ts > 253402300799ULL)
107             ts /= 1000;
108           repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts);
109         }
110       else
111         type = jsonparser_skip(jp, type);
112     }
113   if (fn || kfn)
114     repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
115   solv_free(fn);
116   solv_free(subdir);
117   if (!s->evr)
118     s->evr = 1;
119   if (s->name)
120     s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
121   return type;
122 }
123
124 static int
125 parse_packages(struct parsedata *pd, struct solv_jsonparser *jp)
126 {
127   int type = JP_OBJECT;
128   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
129     {
130       if (type == JP_OBJECT)
131         {
132           char *fn = solv_strdup(jp->key);
133           type = parse_package(pd, jp, fn);
134           solv_free(fn);
135         }
136       else
137         type = jsonparser_skip(jp, type);
138     }
139   return type;
140 }
141
142 static int
143 parse_packages2(struct parsedata *pd, struct solv_jsonparser *jp)
144 {
145   int type = JP_ARRAY;
146   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
147     {
148       if (type == JP_OBJECT)
149         type = parse_package(pd, jp, 0);
150       else
151         type = jsonparser_skip(jp, type);
152     }
153   return type;
154 }
155
156 static int
157 parse_main(struct parsedata *pd, struct solv_jsonparser *jp)
158 {
159   int type = JP_OBJECT;
160   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
161     {
162       if (type == JP_OBJECT && !strcmp("packages", jp->key))
163         type = parse_packages(pd, jp);
164       if (type == JP_ARRAY && !strcmp("packages", jp->key))
165         type = parse_packages2(pd, jp);
166       else
167         type = jsonparser_skip(jp, type);
168     }
169   return type;
170 }
171
172 int
173 repo_add_conda(Repo *repo, FILE *fp, int flags)
174 {
175   Pool *pool = repo->pool;
176   struct solv_jsonparser jp;
177   struct parsedata pd;
178   Repodata *data;
179   int type, ret = 0;
180
181   data = repo_add_repodata(repo, flags);
182
183   memset(&pd, 0, sizeof(pd));
184   pd.pool = pool;
185   pd.repo = repo;
186   pd.data = data;
187
188   jsonparser_init(&jp, fp);
189   if ((type = jsonparser_parse(&jp)) != JP_OBJECT)
190     ret = pool_error(pool, -1, "repository does not start with an object");
191   else if ((type = parse_main(&pd, &jp)) != JP_OBJECT_END)
192     ret = pool_error(pool, -1, "parse error line %d", jp.line);
193   jsonparser_free(&jp);
194
195   if (!(flags & REPO_NO_INTERNALIZE))
196     repodata_internalize(data);
197
198   return ret;
199 }
200