Revert "Add support for Recommends:, Suggests:, Supplements: and Enhances:"
[platform/upstream/rpm.git] / build / spec.c
1 /** \ingroup rpmbuild
2  * \file build/spec.c
3  * Handle spec data structure.
4  */
5
6 #include "system.h"
7
8 #include <rpm/header.h>
9 #include <rpm/rpmds.h>
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmts.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmfileutil.h>
14
15 #include "rpmio/rpmlua.h"
16 #include "build/rpmbuild_internal.h"
17
18 #include "debug.h"
19
20 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
21
22 /**
23  * @param p             trigger entry chain
24  * @return              NULL always
25  */
26 static inline
27 struct TriggerFileEntry * freeTriggerFiles(struct TriggerFileEntry * p)
28 {
29     struct TriggerFileEntry *o, *q = p;
30     
31     while (q != NULL) {
32         o = q;
33         q = q->next;
34         o->fileName = _free(o->fileName);
35         o->script = _free(o->script);
36         o->prog = _free(o->prog);
37         free(o);
38     }
39     return NULL;
40 }
41
42 /**
43  * Destroy source component chain.
44  * @param s             source component chain
45  * @return              NULL always
46  */
47 static inline
48 struct Source * freeSources(struct Source * s)
49 {
50     struct Source *r, *t = s;
51
52     while (t != NULL) {
53         r = t;
54         t = t->next;
55         r->fullSource = _free(r->fullSource);
56         free(r);
57     }
58     return NULL;
59 }
60
61 rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
62 {
63     const char *pname;
64     char *fullName = NULL;
65     Package p;
66
67     /* "main" package */
68     if (name == NULL) {
69         if (pkg)
70             *pkg = spec->packages;
71         return RPMRC_OK;
72     }
73
74     /* Construct package name */
75     if (flag == PART_SUBNAME) {
76         pname = headerGetString(spec->packages->header, RPMTAG_NAME);
77         rasprintf(&fullName, "%s-%s", pname, name);
78     } else {
79         fullName = xstrdup(name);
80     }
81
82     /* Locate package with fullName */
83     for (p = spec->packages; p != NULL; p = p->next) {
84         pname = headerGetString(p->header, RPMTAG_NAME);
85         if (pname && (rstreq(fullName, pname))) {
86             break;
87         }
88     }
89     free(fullName);
90
91     if (pkg)
92         *pkg = p;
93     return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
94 }
95
96 Package newPackage(rpmSpec spec)
97 {
98     Package p = xcalloc(1, sizeof(*p));
99     p->header = headerNew();
100     p->autoProv = 1;
101     p->autoReq = 1;
102     p->fileList = NULL;
103     p->fileFile = NULL;
104     p->policyList = NULL;
105
106     if (spec->packages == NULL) {
107         spec->packages = p;
108     } else {
109         Package pp;
110         /* Always add package to end of list */
111         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
112             {};
113         pp->next = p;
114     }
115     p->next = NULL;
116
117     return p;
118 }
119
120 static Package freePackage(Package pkg)
121 {
122     if (pkg == NULL) return NULL;
123     
124     pkg->preInFile = _free(pkg->preInFile);
125     pkg->postInFile = _free(pkg->postInFile);
126     pkg->preUnFile = _free(pkg->preUnFile);
127     pkg->postUnFile = _free(pkg->postUnFile);
128     pkg->verifyFile = _free(pkg->verifyFile);
129
130     pkg->header = headerFree(pkg->header);
131     pkg->ds = rpmdsFree(pkg->ds);
132     pkg->fileList = argvFree(pkg->fileList);
133     pkg->fileFile = argvFree(pkg->fileFile);
134     pkg->policyList = argvFree(pkg->policyList);
135     pkg->cpioList = rpmfiFree(pkg->cpioList);
136
137     pkg->icon = freeSources(pkg->icon);
138     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
139
140     free(pkg);
141     return NULL;
142 }
143
144 static Package freePackages(Package packages)
145 {
146     Package p;
147
148     while ((p = packages) != NULL) {
149         packages = p->next;
150         p->next = NULL;
151         freePackage(p);
152     }
153     return NULL;
154 }
155
156 rpmSpec newSpec(void)
157 {
158     rpmSpec spec = xcalloc(1, sizeof(*spec));
159     
160     spec->specFile = NULL;
161
162     spec->fileStack = NULL;
163     spec->lbufSize = BUFSIZ * 10;
164     spec->lbuf = xmalloc(spec->lbufSize);
165     spec->lbuf[0] = '\0';
166     spec->line = spec->lbuf;
167     spec->nextline = NULL;
168     spec->nextpeekc = '\0';
169     spec->lineNum = 0;
170     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
171     spec->readStack->next = NULL;
172     spec->readStack->reading = 1;
173
174     spec->rootDir = NULL;
175     spec->prep = NULL;
176     spec->build = NULL;
177     spec->install = NULL;
178     spec->check = NULL;
179     spec->clean = NULL;
180     spec->parsed = NULL;
181
182     spec->sources = NULL;
183     spec->packages = NULL;
184     spec->noSource = 0;
185     spec->numSources = 0;
186
187     spec->sourceRpmName = NULL;
188     spec->sourcePkgId = NULL;
189     spec->sourceHeader = NULL;
190     spec->sourceCpioList = NULL;
191     
192     spec->buildRoot = NULL;
193     spec->buildSubdir = NULL;
194
195     spec->buildRestrictions = headerNew();
196     spec->BANames = NULL;
197     spec->BACount = 0;
198     spec->recursing = 0;
199     spec->BASpecs = NULL;
200
201     spec->flags = RPMSPEC_NONE;
202
203     spec->macros = rpmGlobalMacroContext;
204     
205 #ifdef WITH_LUA
206     {
207     /* make sure patches and sources tables always exist */
208     rpmlua lua = NULL; /* global state */
209     rpmluaPushTable(lua, "patches");
210     rpmluaPushTable(lua, "sources");
211     rpmluaPop(lua);
212     rpmluaPop(lua);
213     }
214 #endif
215     return spec;
216 }
217
218 rpmSpec rpmSpecFree(rpmSpec spec)
219 {
220
221     if (spec == NULL) return NULL;
222
223     spec->prep = freeStringBuf(spec->prep);
224     spec->build = freeStringBuf(spec->build);
225     spec->install = freeStringBuf(spec->install);
226     spec->check = freeStringBuf(spec->check);
227     spec->clean = freeStringBuf(spec->clean);
228     spec->parsed = freeStringBuf(spec->parsed);
229
230     spec->buildRoot = _free(spec->buildRoot);
231     spec->buildSubdir = _free(spec->buildSubdir);
232     spec->specFile = _free(spec->specFile);
233
234     closeSpec(spec);
235
236     while (spec->readStack) {
237         struct ReadLevelEntry *rl = spec->readStack;
238         spec->readStack = rl->next;
239         rl->next = NULL;
240         free(rl);
241     }
242     spec->lbuf = _free(spec->lbuf);
243     
244     spec->sourceRpmName = _free(spec->sourceRpmName);
245     spec->sourcePkgId = _free(spec->sourcePkgId);
246     spec->sourceHeader = headerFree(spec->sourceHeader);
247     spec->sourceCpioList = rpmfiFree(spec->sourceCpioList);
248
249     spec->buildRestrictions = headerFree(spec->buildRestrictions);
250
251     if (!spec->recursing) {
252         if (spec->BASpecs != NULL)
253         while (spec->BACount--) {
254             spec->BASpecs[spec->BACount] =
255                         rpmSpecFree(spec->BASpecs[spec->BACount]);
256         }
257         spec->BASpecs = _free(spec->BASpecs);
258     }
259     spec->BANames = _free(spec->BANames);
260
261 #ifdef WITH_LUA
262     rpmlua lua = NULL; /* global state */
263     rpmluaDelVar(lua, "patches");
264     rpmluaDelVar(lua, "sources");       
265 #endif
266
267     spec->sources = freeSources(spec->sources);
268     spec->packages = freePackages(spec->packages);
269     
270     spec = _free(spec);
271
272     return spec;
273 }
274
275 Header rpmSpecSourceHeader(rpmSpec spec)
276 {
277         return spec->sourceHeader;
278 }
279
280 rpmds rpmSpecDS(rpmSpec spec, rpmTagVal tag)
281 {
282     return (spec != NULL) ? rpmdsNew(spec->buildRestrictions, tag, 0) : NULL;
283 }
284
285 rpmps rpmSpecCheckDeps(rpmts ts, rpmSpec spec)
286 {
287     rpmps probs = NULL;
288
289     rpmtsEmpty(ts);
290
291     rpmtsAddInstallElement(ts, rpmSpecSourceHeader(spec), NULL, 0, NULL);
292     rpmtsCheck(ts);
293     probs = rpmtsProblems(ts);
294
295     rpmtsEmpty(ts);
296     return probs;
297 }
298
299 struct rpmSpecIter_s {
300     void *next;
301 };
302
303 #define SPEC_LISTITER_INIT(_itertype, _iteritem)        \
304     _itertype iter = NULL;                              \
305     if (spec) {                                         \
306         iter = xcalloc(1, sizeof(*iter));               \
307         iter->next = spec->_iteritem;                   \
308     }                                                   \
309     return iter
310
311 #define SPEC_LISTITER_NEXT(_valuetype)                  \
312     _valuetype item = NULL;                             \
313     if (iter) {                                         \
314         item = iter->next;                              \
315         iter->next = (item) ? item->next : NULL;        \
316     }                                                   \
317     return item
318
319 #define SPEC_LISTITER_FREE()                            \
320     free(iter);                                         \
321     return NULL
322
323
324 rpmSpecPkgIter rpmSpecPkgIterInit(rpmSpec spec)
325 {
326     SPEC_LISTITER_INIT(rpmSpecPkgIter, packages);
327 }
328
329 rpmSpecPkgIter rpmSpecPkgIterFree(rpmSpecPkgIter iter)
330 {
331     SPEC_LISTITER_FREE();
332 }
333
334 rpmSpecPkg rpmSpecPkgIterNext(rpmSpecPkgIter iter)
335 {
336     SPEC_LISTITER_NEXT(rpmSpecPkg);
337 }
338
339 Header rpmSpecPkgHeader(rpmSpecPkg pkg)
340 {
341     return (pkg != NULL) ? pkg->header : NULL;
342 }
343
344 rpmSpecSrcIter rpmSpecSrcIterInit(rpmSpec spec)
345 {
346     SPEC_LISTITER_INIT(rpmSpecSrcIter, sources);
347 }
348
349 rpmSpecSrcIter rpmSpecSrcIterFree(rpmSpecSrcIter iter)
350 {
351     SPEC_LISTITER_FREE();
352 }
353
354 rpmSpecSrc rpmSpecSrcIterNext(rpmSpecSrcIter iter)
355 {
356     SPEC_LISTITER_NEXT(rpmSpecSrc);
357 }
358
359 rpmSourceFlags rpmSpecSrcFlags(rpmSpecSrc src)
360 {
361     return (src != NULL) ? src->flags : 0;
362 }
363
364 int rpmSpecSrcNum(rpmSpecSrc src)
365 {
366     return (src != NULL) ? src->num : -1;
367 }
368
369 const char * rpmSpecSrcFilename(rpmSpecSrc src, int full)
370 {
371     const char *source = NULL;
372     if (src) {
373         source = full ? src->fullSource : src->source;
374     }
375     return source;
376 }
377
378 const char * rpmSpecGetSection(rpmSpec spec, int section)
379 {
380     if (spec) {
381         switch (section) {
382         case RPMBUILD_NONE:     return getStringBuf(spec->parsed);
383         case RPMBUILD_PREP:     return getStringBuf(spec->prep);
384         case RPMBUILD_BUILD:    return getStringBuf(spec->build);
385         case RPMBUILD_INSTALL:  return getStringBuf(spec->install);
386         case RPMBUILD_CHECK:    return getStringBuf(spec->check);
387         case RPMBUILD_CLEAN:    return getStringBuf(spec->clean);
388         }
389     }
390     return NULL;
391 }
392
393 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
394 {
395     rpmSpec spec = NULL;
396     int res = 1;
397
398     if (qva->qva_showPackage == NULL)
399         goto exit;
400
401     spec = rpmSpecParse(arg, (RPMSPEC_ANYARCH|RPMSPEC_FORCE), NULL);
402     if (spec == NULL) {
403         rpmlog(RPMLOG_ERR,
404                         _("query of specfile %s failed, can't parse\n"), arg);
405         goto exit;
406     }
407
408     if (qva->qva_source == RPMQV_SPECRPMS) {
409         res = 0;
410         for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
411 #if 0
412             /*
413              * XXX FIXME: whether to show all or just the packages that
414              * would be built needs to be made caller specifiable, for now
415              * revert to "traditional" behavior as existing tools rely on this.
416              */
417             if (pkg->fileList == NULL) continue;
418 #endif
419             res += qva->qva_showPackage(qva, ts, pkg->header);
420         }
421     } else {
422         res = qva->qva_showPackage(qva, ts, spec->sourceHeader);
423     }
424
425 exit:
426     rpmSpecFree(spec);
427     return res;
428 }