/* * Parses RPM spec file into Makefile fragment. See * * http://fedora.redhat.com/docs/drafts/rpm-guide-en/ch-programming-c.html * * Mark Huang * Copyright (C) 2006 The Trustees of Princeton University * */ #include #include #include #include #include #include #include #include #include #include /* from f10 and up, Spec is renamed rpmSpec */ #ifndef _RPMTYPES_H #define rpmSpec Spec #endif #define MAX_WHITELIST_SIZE 16 #ifndef PATH_MAX #include #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 [ | | ]:", 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) 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;isources; 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 "-WHITELIST-RPMS" tag in the tags file. */ for (i=0;ifileList || 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; }