forked from planetlab/build
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspec2make.c
More file actions
258 lines (222 loc) · 7.63 KB
/
spec2make.c
File metadata and controls
258 lines (222 loc) · 7.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
* Parses RPM spec file into Makefile fragment. See
*
* http://fedora.redhat.com/docs/drafts/rpm-guide-en/ch-programming-c.html
*
* Mark Huang <mlhuang@cs.princeton.edu>
* Copyright (C) 2006 The Trustees of Princeton University
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
#include <rpm/rpmcli.h>
#include <rpm/rpmbuild.h>
#include <rpm/rpmspec.h>
/* from f10 and up, Spec is renamed rpmSpec */
#ifndef _RPMTYPES_H
#define rpmSpec Spec
#endif
#define MAX_WHITELIST_SIZE 16
#ifndef PATH_MAX
#include <linux/limits.h>
#endif
extern size_t strnlen(const char *s, size_t maxlen);
/* the structure describing the options we take and the defaults */
static struct poptOption optionsTable[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
"Build options with [ <specfile> | <tarball> | <source package> ]:",
NULL },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
"Common options for all rpm modes and executables:",
NULL },
POPT_AUTOALIAS
POPT_AUTOHELP
POPT_TABLEEND
};
/* Stolen from rpm/build/spec.c:rpmspecQuery() */
rpmSpec
rpmspecGet(rpmts ts, const char * arg)
{
char * buildRoot = NULL;
int recursing = 0;
char * passPhrase = "";
char *cookie = NULL;
int anyarch = 1;
int force = 1;
if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
cookie, anyarch, force)) {
fprintf(stderr, "query of specfile %s failed, can't parse\n", arg);
return NULL;
}
return rpmtsSpec(ts);
}
int
main(int argc, char *argv[])
{
poptContext context;
rpmts ts = NULL;
int ec = 0;
rpmSpec spec;
struct Source *source;
Package pkg;
const char *name, *version, *release, *arch, *unused;
const char *package_name;
char **package_whitelist;
/* BEGIN: support to pull out --target from the args list */
int alen, i;
char *target = NULL;
int args = 1;
int whitelist_size=0;
package_whitelist = (char **) malloc(MAX_WHITELIST_SIZE * sizeof(char *));
if (!package_whitelist) {
perror("Could not allocate package whitelist\n");
exit(1);
}
/* walk argv list looking for options */
while ((args+1)<argc) {
/* whitelist-rpms are packages that need to be considered even if the parsing logic of spec2make (second half of this file) concludes otherwise */
if (strcmp(argv[args],"--whitelist-rpms")==0) {
/* Split "whitelist-rpms" which is a comma-separated list, remove --whitelist-rpms <option> from argv */
int option_offset = 1;
char *whitelist_str = argv[args+1];
if (whitelist_str != NULL) {
char *saveptr = NULL, *str;
option_offset = 2;
for (str = whitelist_str; ; str = NULL) {
char *token;
token = strtok_r(str, "," , &saveptr);
if (token == NULL) break;
package_whitelist[whitelist_size++] = token;
}
}
for (i=args;i<argc-2+option_offset;i++) argv[i]=argv[i+option_offset];
argc-=option_offset;
} else if (strcmp(argv[args],"--target")==0) {
char **dash;
/* get arch component of the --target option */
dash = (char**)strchr(argv[args+1],'-');
if (dash != NULL) *dash=NULL;
/* copy arch component of --target option to target */
alen = strnlen(argv[args+1],32);
target = (char*)malloc(alen+1);
if (target == NULL) return errno;
strncpy(target,argv[args+1],alen);
target[alen]='\0';
/* change argc, argv to take out the "--target xxx" */
for (i=args;i<argc;i++) argv[i]=argv[i+2];
argc-=2;
break;
}
else
args++;
}
argv[1]=argv[argc-2];
argv[2]=argv[argc-1];
argv[3]=0;
argc=3;
/* END: support to pull out --target from the args list */
/* Parse common options for all rpm modes and executables */
context = rpmcliInit(argc, argv, optionsTable);
/* Create transaction state */
ts = rpmtsCreate();
/* Parse spec file. The rpmcli functions don't allow you to
* access the Spec structure directly, so we call our own
* version of rpmSpecQuery() directly. */
spec = rpmspecGet(ts, argv[1]);
package_name = argv[2];
if (!spec) {
ec = 1;
goto done;
}
/* Print sources */
for (source = spec->sources; source; source = source->next) {
char fullSource[PATH_MAX];
strncpy(fullSource, source->fullSource, sizeof(fullSource));
printf("%s.tarballs += SOURCES/%s\n", package_name, basename(fullSource));
/* computes the SOURCEDIR variable by removing .tar.gz or .tar.bz2 */
{
char *suffixes[] = {".tar.gz",".tgz",".tar.bz2", NULL};
char **suffix;
char *suffix_index;
for (suffix=suffixes ; *suffix ; suffix++) {
/*printf("# trying %s\n",*suffix);*/
suffix_index=strstr(fullSource,*suffix);
if (suffix_index) {
char sourcename[PATH_MAX];
size_t len = (size_t)(suffix_index-fullSource);
strncpy(sourcename,fullSource,len);
sourcename[len]='\0';
printf ("%s.source := SOURCES/%s\n",package_name,basename(sourcename));
break;
}
}
}
}
/* Get SRPM name from name of first package */
pkg = spec->packages;
name = version = release = NULL;
(void) headerNVR(pkg->header, &name, &version, &release);
if (name && version && release)
printf("%s.srpm := SRPMS/%s-%s-%s.src.rpm\n",
package_name, name, version, release);
/* Print non-empty packages */
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
int force = 0;
name = version = release = arch = NULL;
(void) headerNEVRA(pkg->header, &name, &unused, &version, &release, &arch);
if (name && version && release && arch) {
if (target != NULL) {
if (strcmp(arch,target)!=0) {
arch=target;
}
}
/* skip empty packages
*
* Unfortunately, f8 + the RHEL kernel break this bit of cleverness. The following
* line returns false for the kernel-devel package even though it is not empty thereby breaking the build.
* Rather than unfolding the kernel package macros in the current specfile,
* this hack should work till f8 dies its natural death.
* To add rpms that are exempted in this way, add a "<package>-WHITELIST-RPMS" tag in the tags file.
*/
for (i=0;i<whitelist_size;i++) if (strncmp(package_whitelist[i], name, strlen(name)) == 0) force = 1;
if (pkg->fileList || force) {
/* attach (add) rpm path to package */
printf("%s.rpms += RPMS/%s/%s-%s-%s.%s.rpm\n",
package_name, arch, name, version, release, arch);
/* convenience */
printf("%s.rpmnames += %s\n",
package_name, name);
/* attach path to rpm name */
printf("%s.rpm-path := RPMS/%s/%s-%s-%s.%s.rpm\n",
name,arch, name, version, release, arch);
/* attach package to rpm name for backward resolution - should be unique */
printf("%s.package := %s\n",
name,package_name);
}
}
}
/* export some macros to make */
/* note : this relies on pl-specific conventions and might be wrong */
{
char *macros[] = { "release" , "name" , "version" , "taglevel" , NULL } ;
char **nav;
char *macro=malloc(32);
for (nav=macros; *nav; nav++) {
sprintf(macro,"%%{%s}",*nav);
char *value = rpmExpand(macro,NULL);
printf ("%s.rpm-%s := %s\n",package_name,*nav,value);
}
}
/* export arch */
printf ("%s.rpm-arch := %s\n",package_name,target);
spec = freeSpec(spec);
done:
ts = rpmtsFree(ts);
context = rpmcliFini(context);
return ec;
}