resurrect toplevel tar target.
[platform/upstream/rpm.git] / build.c
1 #include "system.h"
2
3 #include "build/rpmbuild.h"
4 #include "popt/popt.h"
5 #include "build.h"
6 #include "install.h"
7
8 static int checkSpec(Header h)
9 {
10     char *rootdir = NULL;
11     rpmdb db = NULL;
12     int mode = O_RDONLY;
13     rpmTransactionSet ts;
14     struct rpmDependencyConflict * conflicts;
15     int numConflicts;
16     int rc;
17
18     if (!headerIsEntry(h, RPMTAG_REQUIREFLAGS))
19         return 0;
20
21     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
22         const char *dn;
23         dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
24         rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
25         xfree(dn);
26         exit(EXIT_FAILURE);
27     }
28     ts = rpmtransCreateSet(db, rootdir);
29
30     rc = rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
31
32     rc = rpmdepCheck(ts, &conflicts, &numConflicts);
33     if (rc == 0 && conflicts) {
34         rpmMessage(RPMMESS_ERROR, _("failed build prerequisites:\n"));
35         printDepProblems(stderr, conflicts, numConflicts);
36         rpmdepFreeConflicts(conflicts, numConflicts);
37         rc = 1;
38     }
39
40     if (ts)
41         rpmtransFree(ts);
42     if (db)
43         rpmdbClose(db);
44
45     return rc;
46 }
47
48 static int buildForTarget(const char *arg, struct rpmBuildArguments *ba,
49         const char *passPhrase, int fromTarball, char *cookie,
50         int force, int nodeps)
51 {
52     int buildAmount = ba->buildAmount;
53     const char *buildRoot = ba->buildRootOverride;
54     int test = ba->noBuild;
55
56     FILE *f;
57     const char * specfile;
58     int res = 0;
59     struct stat statbuf;
60     char * s;
61     int count, fd;
62     char buf[BUFSIZ];
63     Spec spec = NULL;
64
65     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
66
67     if (fromTarball) {
68         const char *specDir;
69         const char * tmpSpecFile;
70         char * cmd, *s;
71
72         specDir = rpmGetPath("%{_specdir}", NULL);
73
74         {   char tfn[64];
75             strcpy(tfn, "rpm-spec.XXXXXX");
76             tmpSpecFile = rpmGetPath("%{_specdir}/", mktemp(tfn), NULL);
77         }
78
79         cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
80         sprintf(cmd, "gunzip < %s | tar xOvf - Specfile 2>&1 > %s",
81                         arg, tmpSpecFile);
82         if (!(f = popen(cmd, "r"))) {
83             fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
84                         strerror(errno));
85             xfree(specDir);
86             xfree(tmpSpecFile);
87             return 1;
88         }
89         if ((!fgets(buf, sizeof(buf) - 1, f)) || !strchr(buf, '/')) {
90             /* Try again */
91             pclose(f);
92
93             sprintf(cmd, "gunzip < %s | tar xOvf - \\*.spec 2>&1 > %s", arg,
94                     tmpSpecFile);
95             if (!(f = popen(cmd, "r"))) {
96                 fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
97                         strerror(errno));
98                 xfree(specDir);
99                 xfree(tmpSpecFile);
100                 return 1;
101             }
102             if (!fgets(buf, sizeof(buf) - 1, f)) {
103                 /* Give up */
104                 fprintf(stderr, _("Failed to read spec file from %s\n"), arg);
105                 unlink(tmpSpecFile);
106                 xfree(specDir);
107                 xfree(tmpSpecFile);
108                 return 1;
109             }
110         }
111         pclose(f);
112
113         cmd = s = buf;
114         while (*cmd) {
115             if (*cmd == '/') s = cmd + 1;
116             cmd++;
117         }
118
119         cmd = s;
120
121         /* remove trailing \n */
122         s = cmd + strlen(cmd) - 1;
123         *s = '\0';
124
125         s = alloca(strlen(specDir) + strlen(cmd) + 5);
126         sprintf(s, "%s/%s", specDir, cmd);
127         
128         if (rename(tmpSpecFile, s)) {
129             fprintf(stderr, _("Failed to rename %s to %s: %s\n"),
130                     tmpSpecFile, s, strerror(errno));
131             unlink(tmpSpecFile);
132             xfree(specDir);
133             xfree(tmpSpecFile);
134             return 1;
135         }
136
137         /* Make the directory which contains the tarball the source 
138            directory for this run */
139
140         if (*arg != '/') {
141             (void)getcwd(buf, BUFSIZ);
142             strcat(buf, "/");
143             strcat(buf, arg);
144         } else 
145             strcpy(buf, arg);
146
147         cmd = buf + strlen(buf) - 1;
148         while (*cmd != '/') cmd--;
149         *cmd = '\0';
150
151         addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
152         xfree(specDir);
153         xfree(tmpSpecFile);
154         specfile = s;
155     } else if (arg[0] == '/') {
156         specfile = arg;
157     } else {
158         char *s = alloca(BUFSIZ);
159         (void)getcwd(s, BUFSIZ);
160         strcat(s, "/");
161         strcat(s, arg);
162         specfile = s;
163     }
164
165     stat(specfile, &statbuf);
166     if (! S_ISREG(statbuf.st_mode)) {
167         fprintf(stderr, _("File is not a regular file: %s\n"), specfile);
168         return 1;
169     }
170     
171     if ((fd = open(specfile, O_RDONLY)) < 0) {
172         fprintf(stderr, _("Unable to open spec file: %s\n"), specfile);
173         return 1;
174     }
175     count = read(fd, buf, sizeof(buf) < 128 ? sizeof(buf) : 128);
176     close(fd);
177     s = buf;
178     while(count--) {
179         if (! (isprint(*s) || isspace(*s) || (*s == 0x1b))) {
180             fprintf(stderr, _("File contains non-printable characters(%c): %s\n"), *s,
181                     specfile);
182             return 1;
183         }
184         s++;
185     }
186
187     /* Parse the spec file */
188 #define _anyarch(_f)    \
189 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
190     if (parseSpec(&spec, specfile, buildRoot, 0, passPhrase, cookie,
191         _anyarch(buildAmount), force)) {
192             return 1;
193     }
194 #undef  _anyarch
195
196     /* Assemble source header from parsed components */
197     initSourceHeader(spec);
198
199     /* Check build prerequisites */
200     if (!nodeps && checkSpec(spec->sourceHeader)) {
201         freeSpec(spec);
202         return 1;
203     }
204
205     if (buildSpec(spec, buildAmount, test)) {
206         freeSpec(spec);
207         return 1;
208     }
209     
210     if (fromTarball) unlink(specfile);
211
212     freeSpec(spec);
213     
214     return res;
215 }
216
217 int build(const char *arg, struct rpmBuildArguments *ba, const char *passPhrase,
218           int fromTarball, char *cookie, const char * rcfile, int force,
219           int nodeps)
220 {
221     char *t, *te;
222     int rc;
223     char *targets = ba->targets;
224
225     if (targets == NULL) {
226         rc =  buildForTarget(arg, ba, passPhrase, fromTarball, cookie,
227                 force, nodeps);
228         return rc;
229     }
230
231     /* parse up the build operators */
232
233     printf(_("Building target platforms: %s\n"), targets);
234
235     for (t = targets; *t != '\0'; t = te) {
236         char *target;
237         if ((te = strchr(t, ',')) == NULL)
238             te = t + strlen(t);
239         target = alloca(te-t+1);
240         strncpy(target, t, (te-t));
241         target[te-t] = '\0';
242         printf(_("Building for target %s\n"), target);
243
244         rpmReadConfigFiles(rcfile, target);
245         rc = buildForTarget(arg, ba, passPhrase, fromTarball, cookie,
246                 force, nodeps);
247         if (rc)
248             return rc;
249
250         freeMacros(NULL);
251     }
252
253     return 0;
254 }
255
256 #define POPT_USECATALOG         1000
257 #define POPT_NOLANG             1001
258 #define POPT_RMSOURCE           1002
259 #define POPT_RMBUILD            1003
260 #define POPT_BUILDROOT          1004
261 #define POPT_BUILDARCH          1005
262 #define POPT_BUILDOS            1006
263 #define POPT_TARGETPLATFORM     1007
264 #define POPT_NOBUILD            1008
265 #define POPT_SHORTCIRCUIT       1009
266 #define POPT_RMSPEC             1010
267
268 extern int noLang;
269 static int noBuild = 0;
270 static int useCatalog = 0;
271
272 static void buildArgCallback(poptContext con, enum poptCallbackReason reason,
273                              const struct poptOption * opt, const char * arg,
274                              struct rpmBuildArguments * data)
275 {
276     switch (opt->val) {
277     case POPT_USECATALOG: data->useCatalog = 1; break;
278     case POPT_NOBUILD: data->noBuild = 1; break;
279     case POPT_NOLANG: data->noLang = 1; break;
280     case POPT_SHORTCIRCUIT: data->shortCircuit = 1; break;
281     case POPT_RMSOURCE: data->buildAmount |= RPMBUILD_RMSOURCE; break;
282     case POPT_RMSPEC: data->buildAmount |= RPMBUILD_RMSPEC; break;
283     case POPT_RMBUILD: data->buildAmount |= RPMBUILD_RMBUILD; break;
284     case POPT_BUILDROOT:
285         if (data->buildRootOverride) {
286             fprintf(stderr, _("buildroot already specified"));
287             exit(EXIT_FAILURE);
288         }
289         data->buildRootOverride = strdup(arg);
290         break;
291     case POPT_BUILDARCH:
292         fprintf(stderr, _("--buildarch has been obsoleted.  Use the --target option instead.\n")); 
293         exit(EXIT_FAILURE);
294         break;
295     case POPT_BUILDOS:
296         fprintf(stderr, _("--buildos has been obsoleted.  Use the --target option instead.\n")); 
297         exit(EXIT_FAILURE);
298         break;
299     case POPT_TARGETPLATFORM:
300         if (data->targets) {
301             int len = strlen(data->targets) + strlen(arg) + 2;
302             data->targets = realloc(data->targets, len);
303             strcat(data->targets, ",");
304         } else {
305             data->targets = malloc(strlen(arg) + 1);
306             data->targets[0] = '\0';
307         }
308         strcat(data->targets, arg);
309         break;
310     }
311 }
312
313 struct poptOption rpmBuildPoptTable[] = {
314         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
315                 buildArgCallback, 0, NULL, NULL },
316         { "buildarch", '\0', POPT_ARG_STRING, 0,  POPT_BUILDARCH,
317                 N_("override build architecture"), "ARCH" },
318         { "buildos", '\0', POPT_ARG_STRING, 0,  POPT_BUILDOS,
319                 N_("override build operating system"), "OS" },
320         { "buildroot", '\0', POPT_ARG_STRING, 0,  POPT_BUILDROOT,
321                 N_("override build root"), "DIRECTORY" },
322         { "clean", '\0', 0, 0, POPT_RMBUILD,
323                 N_("remove build tree when done"), NULL},
324         { "nobuild", '\0', 0, &noBuild,  POPT_NOBUILD,
325                 N_("do not execute any stages of the build"), NULL },
326         { "nolang", '\0', 0, &noLang, POPT_NOLANG,
327                 N_("do not accept I18N msgstr's from specfile"), NULL},
328         { "rmsource", '\0', 0, 0, POPT_RMSOURCE,
329                 N_("remove sources when done"), NULL},
330         { "rmspec", '\0', 0, 0, POPT_RMSPEC,
331                 N_("remove specfile when done"), NULL},
332         { "short-circuit", '\0', 0, 0,  POPT_SHORTCIRCUIT,
333                 N_("skip straight to specified stage (only for c,i)"), NULL },
334         { "target", '\0', POPT_ARG_STRING, 0,  POPT_TARGETPLATFORM,
335                 N_("override target platform"), "CPU-VENDOR-OS" },
336         { "usecatalog", '\0', 0, &useCatalog, POPT_USECATALOG,
337                 N_("lookup I18N strings in specfile catalog"), NULL},
338         { 0, 0, 0, 0, 0,        NULL, NULL }
339 };