2 * Parse spec file and build package.
9 #include <rpm/rpmcli.h>
10 #include <rpm/rpmtag.h>
11 #include <rpm/rpmlib.h> /* rpmrc, MACHTABLE .. */
12 #include <rpm/rpmbuild.h>
14 #include <rpm/rpmps.h>
15 #include <rpm/rpmte.h>
16 #include <rpm/rpmts.h>
17 #include <rpm/rpmfileutil.h>
18 #include <rpm/rpmlog.h>
25 static int checkSpec(rpmts ts, Header h)
30 if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
31 && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
34 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
38 ps = rpmtsProblems(ts);
39 if (rc == 0 && rpmpsNumProblems(ps) > 0) {
40 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
46 /* XXX nuke the added package. */
54 static int isSpecFile(const char * specfile)
62 f = fopen(specfile, "r");
63 if (f == NULL || ferror(f)) {
64 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
65 specfile, strerror(errno));
68 count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
75 for (s = buf; count--; s++) {
86 if (checking && !(isprint(*s) || isspace(*s))) return 0;
89 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
98 * Try to find a spec from a tarball pointed to by arg.
99 * Return absolute path to spec name on success, otherwise NULL.
101 static char * getTarSpec(const char *arg)
103 char *specFile = NULL;
111 rpmCompressedMagic res = COMPRESSED_OTHER;
113 /* FIX: static zcmds heartburn */
114 static const char *zcmds[] = { "cat", "gunzip", "bunzip2", "cat" };
115 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
117 specDir = rpmGetPath("%{_specdir}", NULL);
118 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
119 tar = rpmGetPath("%{__tar}", NULL);
121 #if defined(HAVE_MKSTEMP)
122 (void) close(mkstemp(tmpSpecFile));
124 (void) mktemp(tmpSpecFile);
127 (void) rpmFileIsCompressed(arg, &res);
129 for (try = tryspec; *try != NULL; try++) {
133 rasprintf(&cmd, "%s < '%s' | %s xOvf - --wildcards %s 2>&1 > '%s'",
134 zcmds[res & 0x3], arg, tar, *try, tmpSpecFile);
136 if (!(fp = popen(cmd, "r"))) {
137 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
139 gotspec = fgets(tarbuf, sizeof(tarbuf) - 1, fp) &&
140 isSpecFile(tmpSpecFile);
150 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
154 specBase = basename(tarbuf);
155 /* remove trailing \n */
156 specBase[strlen(specBase)-1] = '\0';
158 rasprintf(&specFile, "%s/%s", specDir, specBase);
159 res = rename(tmpSpecFile, specFile);
162 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
163 tmpSpecFile, specFile);
169 (void) unlink(tmpSpecFile);
178 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
180 const char * passPhrase = ba->passPhrase;
181 const char * cookie = ba->cookie;
182 int buildAmount = ba->buildAmount;
183 char * buildRootURL = NULL;
184 const char * specFile;
185 char * specURL = NULL;
188 int rc = 1; /* assume failure */
191 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
194 if (ba->buildRootOverride)
195 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
197 if (ba->buildMode == 't') {
198 char *srcdir = NULL, *dir;
200 specURL = getTarSpec(arg);
204 /* Make the directory of the tarball %_sourcedir for this run */
205 /* dirname() may modify contents so extra hoops needed. */
207 srcdir = dir = rpmGetCwd();
210 srcdir = dirname(dir);
212 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
215 specURL = xstrdup(arg);
218 specut = urlPath(specURL, &specFile);
219 if (*specFile != '/') {
220 char *s = alloca(BUFSIZ);
221 if (!getcwd(s, BUFSIZ)) {
222 rpmlog(RPMLOG_ERR, _("getcwd failed: %m\n"));
230 if (specut != URL_IS_DASH) {
232 if (stat(specURL, &st) < 0) {
233 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specURL);
236 if (! S_ISREG(st.st_mode)) {
237 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"),
242 /* Try to verify that the file is actually a specfile */
243 if (!isSpecFile(specURL)) {
245 _("File %s does not appear to be a specfile.\n"), specURL);
250 /* Parse the spec file */
251 #define _anyarch(_f) \
252 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
253 if (parseSpec(ts, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
254 cookie, _anyarch(buildAmount), ba->force))
259 if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
263 /* Assemble source header from parsed components */
264 initSourceHeader(spec);
266 /* Check build prerequisites */
267 if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
271 if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
275 if (ba->buildMode == 't')
276 (void) unlink(specURL);
286 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
290 char * targets = ba->targets;
291 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
292 int cleanFlags = ba->buildAmount & buildCleanMask;
293 rpmVSFlags vsflags, ovsflags;
295 vsflags = rpmExpandNumeric("%{_vsflags_build}");
296 if (ba->qva_flags & VERIFY_DIGEST)
297 vsflags |= _RPMVSF_NODIGESTS;
298 if (ba->qva_flags & VERIFY_SIGNATURE)
299 vsflags |= _RPMVSF_NOSIGNATURES;
300 if (ba->qva_flags & VERIFY_HDRCHK)
301 vsflags |= RPMVSF_NOHDRCHK;
302 ovsflags = rpmtsSetVSFlags(ts, vsflags);
304 if (targets == NULL) {
305 rc = buildForTarget(ts, arg, ba);
309 /* parse up the build operators */
311 printf(_("Building target platforms: %s\n"), targets);
313 ba->buildAmount &= ~buildCleanMask;
314 for (t = targets; *t != '\0'; t = te) {
316 if ((te = strchr(t, ',')) == NULL)
318 target = alloca(te-t+1);
319 strncpy(target, t, (te-t));
323 else /* XXX Perform clean-up after last target build. */
324 ba->buildAmount |= cleanFlags;
326 printf(_("Building for target %s\n"), target);
328 /* Read in configuration for target. */
331 (void) rpmReadConfigFiles(rcfile, target);
332 rc = buildForTarget(ts, arg, ba);
338 vsflags = rpmtsSetVSFlags(ts, ovsflags);
339 /* Restore original configuration. */
342 (void) rpmReadConfigFiles(rcfile, NULL);