- Grand Renaming of rpm data types.
[platform/upstream/rpm.git] / build.c
diff --git a/build.c b/build.c
index c017fd9..5e2e1d8 100644 (file)
--- a/build.c
+++ b/build.c
+/** \ingroup rpmcli
+ * Parse spec file and build package.
+ */
+
 #include "system.h"
 
-#include "build/rpmbuild.h"
-#include "popt/popt.h"
+#include <rpmcli.h>
+#include <rpmbuild.h>
+
+#include "rpmps.h"
+#include "rpmte.h"
+#include "rpmts.h"
+
 #include "build.h"
+#include "debug.h"
 
-#ifdef DYING
-int buildForTarget(char *arg, int buildAmount, char *passPhrase,
-                 char *buildRoot, int fromTarball, int test, char *cookie,
-                 force);
-#endif
+/*@access rpmts @*/    /* XXX compared with NULL @*/
+/*@access rpmdb @*/            /* XXX compared with NULL @*/
+/*@access FD_t @*/             /* XXX compared with NULL @*/
+
+/**
+ */
+static int checkSpec(rpmts ts, Header h)
+       /*@globals fileSystem, internalState @*/
+       /*@modifies ts, h, fileSystem, internalState @*/
+{
+    rpmps ps;
+    int rc;
+
+    if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
+     && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
+       return 0;
+
+    rc = rpmtsAddPackage(ts, h, NULL, 0, NULL);
+
+    rc = rpmtsCheck(ts);
+
+    ps = rpmtsGetProblems(ts);
+    if (rc == 0 && ps) {
+       rpmMessage(RPMMESS_ERROR, _("Failed build dependencies:\n"));
+       printDepProblems(stderr, ps);
+       rc = 1;
+    }
+    ps = rpmpsFree(ps);
 
-static int buildForTarget(const char *arg, int buildAmount, const char *passPhrase,
-                 const char *buildRoot, int fromTarball, int test, char *cookie,
-                 int force)
+    /* XXX nuke the added package. */
+    rpmtsClean(ts);
+
+    return rc;
+}
+
+/*
+ * Kurwa, durni ameryka?ce sobe zawsze my?l?, ?e ca?y ?wiat mówi po
+ * angielsku...
+ */
+/* XXX this is still a dumb test but at least it's i18n aware */
+/**
+ */
+static int isSpecFile(const char * specfile)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
+    char buf[256];
+    const char * s;
+    FD_t fd;
+    int count;
+    int checking;
+
+    fd = Fopen(specfile, "r.ufdio");
+    if (fd == NULL || Ferror(fd)) {
+       rpmError(RPMERR_OPEN, _("Unable to open spec file %s: %s\n"),
+               specfile, Fstrerror(fd));
+       return 0;
+    }
+    count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
+    (void) Fclose(fd);
+
+    checking = 1;
+    for (s = buf; count--; s++) {
+       switch (*s) {
+       case '\r':
+       case '\n':
+           checking = 1;
+           /*@switchbreak@*/ break;
+       case ':':
+           checking = 0;
+           /*@switchbreak@*/ break;
+       default:
+           if (checking && !(isprint(*s) || isspace(*s))) return 0;
+           /*@switchbreak@*/ break;
+       }
+    }
+    return 1;
+}
 
-    FILE *f;
-    const char * specfile;
-    int res = 0;
-    struct stat statbuf;
-    char * s;
-    int count, fd;
+/**
+ */
+static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
+       /*@globals rpmGlobalMacroContext,
+               fileSystem, internalState @*/
+       /*@modifies ts, rpmGlobalMacroContext,
+               fileSystem, internalState @*/
+{
+    const char * passPhrase = ba->passPhrase;
+    const char * cookie = ba->cookie;
+    int buildAmount = ba->buildAmount;
+    const char * buildRootURL = NULL;
+    const char * specFile;
+    const char * specURL;
+    int specut;
     char buf[BUFSIZ];
     Spec spec = NULL;
+    int rc;
 
+#ifndef        DYING
     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
+#endif
+
+    /*@-branchstate@*/
+    if (ba->buildRootOverride)
+       buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
+    /*@=branchstate@*/
 
-    if (fromTarball) {
-       const char *specDir;
+    /*@-compmempass@*/ /* FIX: static zcmds heartburn */
+    if (ba->buildMode == 't') {
+       FILE *fp;
+       const char * specDir;
        const char * tmpSpecFile;
-       char * cmd, *s;
+       char * cmd, * s;
+       rpmCompressedMagic res = COMPRESSED_OTHER;
+       /*@observer@*/ static const char *zcmds[] =
+               { "cat", "gunzip", "bunzip2", "cat" };
 
        specDir = rpmGetPath("%{_specdir}", NULL);
 
+       /* XXX Using mkstemp is difficult here. */
+       /* XXX FWIW, default %{_specdir} is root.root 0755 */
        {   char tfn[64];
            strcpy(tfn, "rpm-spec.XXXXXX");
+           /*@-unrecog@*/
            tmpSpecFile = rpmGetPath("%{_specdir}/", mktemp(tfn), NULL);
+           /*@=unrecog@*/
        }
 
+       (void) isCompressed(arg, &res);
+
        cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
-       sprintf(cmd, "gunzip < %s | tar xOvf - Specfile 2>&1 > %s",
-                       arg, tmpSpecFile);
-       if (!(f = popen(cmd, "r"))) {
-           fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
-                       strerror(errno));
-           xfree(specDir);
-           xfree(tmpSpecFile);
+       sprintf(cmd, "%s < %s | tar xOvf - Specfile 2>&1 > %s",
+                       zcmds[res & 0x3], arg, tmpSpecFile);
+       if (!(fp = popen(cmd, "r"))) {
+           rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
+           specDir = _free(specDir);
+           tmpSpecFile = _free(tmpSpecFile);
            return 1;
        }
-       if ((!fgets(buf, sizeof(buf) - 1, f)) || !strchr(buf, '/')) {
+       if ((!fgets(buf, sizeof(buf) - 1, fp)) || !strchr(buf, '/')) {
            /* Try again */
-           pclose(f);
-
-           sprintf(cmd, "gunzip < %s | tar xOvf - \\*.spec 2>&1 > %s", arg,
-                   tmpSpecFile);
-           if (!(f = popen(cmd, "r"))) {
-               fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
-                       strerror(errno));
-               xfree(specDir);
-               xfree(tmpSpecFile);
+           (void) pclose(fp);
+
+           sprintf(cmd, "%s < %s | tar xOvf - \\*.spec 2>&1 > %s",
+                   zcmds[res & 0x3], arg, tmpSpecFile);
+           if (!(fp = popen(cmd, "r"))) {
+               rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
+               specDir = _free(specDir);
+               tmpSpecFile = _free(tmpSpecFile);
                return 1;
            }
-           if (!fgets(buf, sizeof(buf) - 1, f)) {
+           if (!fgets(buf, sizeof(buf) - 1, fp)) {
                /* Give up */
-               fprintf(stderr, _("Failed to read spec file from %s\n"), arg);
-               unlink(tmpSpecFile);
-               xfree(specDir);
-               xfree(tmpSpecFile);
+               rpmError(RPMERR_READ, _("Failed to read spec file from %s\n"),
+                       arg);
+               (void) unlink(tmpSpecFile);
+               specDir = _free(specDir);
+               tmpSpecFile = _free(tmpSpecFile);
                return 1;
            }
        }
-       pclose(f);
+       (void) pclose(fp);
 
        cmd = s = buf;
-       while (*cmd) {
+       while (*cmd != '\0') {
            if (*cmd == '/') s = cmd + 1;
            cmd++;
        }
@@ -84,17 +189,19 @@ static int buildForTarget(const char *arg, int buildAmount, const char *passPhra
        s = cmd + strlen(cmd) - 1;
        *s = '\0';
 
-       s = alloca(strlen(specDir) + strlen(cmd) + 5);
+       specURL = s = alloca(strlen(specDir) + strlen(cmd) + 5);
        sprintf(s, "%s/%s", specDir, cmd);
+       res = rename(tmpSpecFile, s);
+       specDir = _free(specDir);
        
-       if (rename(tmpSpecFile, s)) {
-           fprintf(stderr, _("Failed to rename %s to %s: %s\n"),
-                   tmpSpecFile, s, strerror(errno));
-           unlink(tmpSpecFile);
-           xfree(specDir);
-           xfree(tmpSpecFile);
+       if (res) {
+           rpmError(RPMERR_RENAME, _("Failed to rename %s to %s: %m\n"),
+                       tmpSpecFile, s);
+           (void) unlink(tmpSpecFile);
+           tmpSpecFile = _free(tmpSpecFile);
            return 1;
        }
+       tmpSpecFile = _free(tmpSpecFile);
 
        /* Make the directory which contains the tarball the source 
           directory for this run */
@@ -110,79 +217,96 @@ static int buildForTarget(const char *arg, int buildAmount, const char *passPhra
        while (*cmd != '/') cmd--;
        *cmd = '\0';
 
-       addMacro(&globalMacroContext, "_sourcedir", NULL, buf, RMIL_TARBALL);
-       xfree(specDir);
-       xfree(tmpSpecFile);
-       specfile = s;
-    } else if (arg[0] == '/') {
-       specfile = arg;
+       addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
     } else {
+       specURL = arg;
+    }
+    /*@=compmempass@*/
+
+    specut = urlPath(specURL, &specFile);
+    if (*specFile != '/') {
        char *s = alloca(BUFSIZ);
        (void)getcwd(s, BUFSIZ);
        strcat(s, "/");
        strcat(s, arg);
-       specfile = s;
+       specURL = s;
     }
 
-    stat(specfile, &statbuf);
-    if (! S_ISREG(statbuf.st_mode)) {
-       fprintf(stderr, _("File is not a regular file: %s\n"), specfile);
-       return 1;
-    }
-    
-    if ((fd = open(specfile, O_RDONLY)) < 0) {
-       fprintf(stderr, _("Unable to open spec file: %s\n"), specfile);
-       return 1;
-    }
-    count = read(fd, buf, sizeof(buf) < 128 ? sizeof(buf) : 128);
-    close(fd);
-    s = buf;
-    while(count--) {
-       if (! (isprint(*s) || isspace(*s))) {
-           fprintf(stderr, _("File contains non-printable characters(%c): %s\n"), *s,
-                   specfile);
-           return 1;
+    if (specut != URL_IS_DASH) {
+       struct stat st;
+       if (Stat(specURL, &st) < 0) {
+           rpmError(RPMERR_STAT, _("failed to stat %s: %m\n"), specURL);
+           rc = 1;
+           goto exit;
+       }
+       if (! S_ISREG(st.st_mode)) {
+           rpmError(RPMERR_NOTREG, _("File %s is not a regular file.\n"),
+               specURL);
+           rc = 1;
+           goto exit;
        }
-       s++;
-    }
 
+       /* Try to verify that the file is actually a specfile */
+       if (!isSpecFile(specURL)) {
+           rpmError(RPMERR_BADSPEC,
+               _("File %s does not appear to be a specfile.\n"), specURL);
+           rc = 1;
+           goto exit;
+       }
+    }
+    
+    /* Parse the spec file */
 #define        _anyarch(_f)    \
 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
-    if (parseSpec(&spec, specfile, buildRoot, 0, passPhrase, cookie,
-       _anyarch(buildAmount), force)) {
-           return 1;
+    if (parseSpec(&spec, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
+               cookie, _anyarch(buildAmount), ba->force)) {
+       rc = 1;
+       goto exit;
     }
 #undef _anyarch
 
-    if (buildSpec(spec, buildAmount, test)) {
-       freeSpec(spec);
-       return 1;
+    /* Assemble source header from parsed components */
+    initSourceHeader(spec);
+
+    /* Check build prerequisites */
+    if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
+       rc = 1;
+       goto exit;
     }
-    
-    if (fromTarball) unlink(specfile);
 
-    freeSpec(spec);
+    if (buildSpec(spec, buildAmount, ba->noBuild)) {
+       rc = 1;
+       goto exit;
+    }
     
-    return res;
+    if (ba->buildMode == 't')
+       (void) Unlink(specURL);
+    rc = 0;
+
+exit:
+    spec = freeSpec(spec);
+    buildRootURL = _free(buildRootURL);
+    return rc;
 }
 
-int build(const char *arg, int buildAmount, const char *passPhrase,
-         const char *buildRoot, int fromTarball, int test, char *cookie,
-          const char * rcfile, char *targets, int force)
+int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
 {
     char *t, *te;
-    int rc;
+    int rc = 0;
+    char * targets = ba->targets;
+#define        buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
+    int cleanFlags = ba->buildAmount & buildCleanMask;
 
     if (targets == NULL) {
-       rc =  buildForTarget(arg, buildAmount, passPhrase, buildRoot,
-               fromTarball, test, cookie, force);
-       return rc;
+       rc =  buildForTarget(ts, arg, ba);
+       goto exit;
     }
 
     /* parse up the build operators */
 
-    printf("Building target platforms: %s\n", targets);
+    printf(_("Building target platforms: %s\n"), targets);
 
+    ba->buildAmount &= ~buildCleanMask;
     for (t = targets; *t != '\0'; t = te) {
        char *target;
        if ((te = strchr(t, ',')) == NULL)
@@ -190,95 +314,25 @@ int build(const char *arg, int buildAmount, const char *passPhrase,
        target = alloca(te-t+1);
        strncpy(target, t, (te-t));
        target[te-t] = '\0';
-       printf("Building for target %s\n", target);
+       if (*te != '\0')
+           te++;
+       else    /* XXX Perform clean-up after last target build. */
+           ba->buildAmount |= cleanFlags;
+
+       printf(_("Building for target %s\n"), target);
 
-       rpmReadConfigFiles(rcfile, target);
-       rc = buildForTarget(arg, buildAmount, passPhrase, buildRoot,
-           fromTarball, test, cookie, force);
+       /* Read in configuration for target. */
+       rpmFreeMacros(NULL);
+       (void) rpmReadConfigFiles(rcfile, target);
+       rc = buildForTarget(ts, arg, ba);
        if (rc)
-           return rc;
+           break;
     }
 
-    return 0;
-}
+exit:
+    /* Restore original configuration. */
+    rpmFreeMacros(NULL);
+    (void) rpmReadConfigFiles(rcfile, NULL);
 
-#define        POPT_USECATALOG         1000
-#define        POPT_NOLANG             1001
-#define        POPT_RMSOURCE           1002
-#define        POPT_RMBUILD            1003
-#define        POPT_BUILDROOT          1004
-#define        POPT_BUILDARCH          1005
-#define        POPT_BUILDOS            1006
-#define        POPT_TARGETPLATFORM     1007
-#define        POPT_NOBUILD            1008
-#define        POPT_SHORTCIRCUIT       1009
-
-extern int noLang;
-static int noBuild = 0;
-static int useCatalog = 0;
-
-static void buildArgCallback(poptContext con, enum poptCallbackReason reason,
-                             const struct poptOption * opt, const char * arg,
-                             struct rpmBuildArguments * data)
-{
-    switch (opt->val) {
-    case POPT_USECATALOG: data->useCatalog = 1; break;
-    case POPT_NOBUILD: data->noBuild = 1; break;
-    case POPT_NOLANG: data->noLang = 1; break;
-    case POPT_SHORTCIRCUIT: data->shortCircuit = 1; break;
-    case POPT_RMSOURCE: data->buildAmount |= RPMBUILD_RMSOURCE; break;
-    case POPT_RMBUILD: data->buildAmount |= RPMBUILD_RMBUILD; break;
-    case POPT_BUILDROOT:
-       if (data->buildRootOverride) {
-           fprintf(stderr, _("buildroot already specified"));
-           exit(EXIT_FAILURE);
-       }
-       data->buildRootOverride = strdup(arg);
-       break;
-    case POPT_BUILDARCH:
-       fprintf(stderr, _("--buildarch has been obsoleted.  Use the --target option instead.\n")); 
-       exit(EXIT_FAILURE);
-       break;
-    case POPT_BUILDOS:
-       fprintf(stderr, _("--buildos has been obsoleted.  Use the --target option instead.\n")); 
-       exit(EXIT_FAILURE);
-       break;
-    case POPT_TARGETPLATFORM:
-       if (data->targets) {
-           int len = strlen(data->targets) + strlen(arg) + 2;
-           data->targets = realloc(data->targets, len);
-           strcat(data->targets, ",");
-       } else {
-           data->targets = malloc(strlen(arg) + 1);
-           data->targets[0] = '\0';
-       }
-       strcat(data->targets, arg);
-       break;
-    }
+    return rc;
 }
-
-struct poptOption rpmBuildPoptTable[] = {
-       { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
-               buildArgCallback, 0, NULL, NULL },
-       { "buildarch", '\0', POPT_ARG_STRING, 0,  POPT_BUILDARCH,
-               N_("override build architecture"), "ARCH" },
-       { "buildos", '\0', POPT_ARG_STRING, 0,  POPT_BUILDOS,
-               N_("override build operating system"), "OS" },
-       { "buildroot", '\0', POPT_ARG_STRING, 0,  POPT_BUILDROOT,
-               N_("override build root"), "DIRECTORY" },
-       { "clean", '\0', 0, 0, POPT_RMBUILD,
-               N_("remove build tree when done"), NULL},
-       { "nobuild", '\0', 0, &noBuild,  POPT_NOBUILD,
-               N_("do not execute any stages of the build"), NULL },
-       { "nolang", '\0', 0, &noLang, POPT_NOLANG,
-               N_("do not accept I18N msgstr's from specfile"), NULL},
-       { "rmsource", '\0', 0, 0, POPT_RMSOURCE,
-               N_("remove sources and specfile when done"), NULL},
-       { "short-circuit", '\0', 0, 0,  POPT_SHORTCIRCUIT,
-               N_("skip straight to specified stage (only for c,i)"), NULL },
-       { "target", '\0', POPT_ARG_STRING, 0,  POPT_TARGETPLATFORM,
-               N_("override target platform"), "CPU-VENDOR-OS" },
-       { "usecatalog", '\0', 0, &useCatalog, POPT_USECATALOG,
-               N_("lookup I18N strings in specfile catalog"), NULL},
-       { 0, 0, 0, 0, 0,        NULL, NULL }
-};