From 55bf9abee25c7d101dce15898ebefcbe77a7d655 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Mon, 28 May 2012 16:31:36 +0300 Subject: [PATCH] Initial support for "special" %license, similar to %doc (ticket #116) - Now that this is relatively sanely doable... make %license with non-absolute paths behave similarly to %doc, only installing to a different directory (%_licensedir) and with different flags: licenses are not generic documentation and should not be skipped on installation even if --nodocs is used. The common practise of stuffing licenses into %doc actually violates various licenses which require the license text to always accompany the software. - While ticket #116 suggests various schemes to reduce disk usage, adding some very special logic to installation code just to deal with these doesn't seem justifiable, given how small the licenses generally are. However with licenses now in their own directory structure (/usr/share/licenses by default), running hardlink on them is trivial for cases where disk space is tight (live images, embedded systems etc) --- build/files.c | 67 +++++++++++++++++++++++++++++++---------------- build/parseSpec.c | 1 + macros.in | 1 + 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/build/files.c b/build/files.c index f0721a14b..459a05e42 100644 --- a/build/files.c +++ b/build/files.c @@ -111,6 +111,7 @@ typedef struct specialDir_s { ARGV_t files; struct AttrRec_s ar; struct AttrRec_s def_ar; + rpmFlags sdtype; } * specialDir; typedef struct FileEntry_s { @@ -845,7 +846,7 @@ static rpmRC parseForSimple(char * buf, FileEntry cur, ARGV_t * fileNames) { char *s, *t; rpmRC res = RPMRC_OK; - int allow_relative = (RPMFILE_PUBKEY|RPMFILE_DOC); + int allow_relative = (RPMFILE_PUBKEY|RPMFILE_DOC|RPMFILE_LICENSE); t = buf; while ((s = strtokWithQuotes(t, " \t\n")) != NULL) { @@ -862,8 +863,8 @@ static rpmRC parseForSimple(char * buf, FileEntry cur, ARGV_t * fileNames) res = RPMRC_FAIL; continue; } - /* non-absolute %doc paths are special */ - if (cur->attrFlags & RPMFILE_DOC) + /* non-absolute %doc and %license paths are special */ + if (cur->attrFlags & (RPMFILE_DOC | RPMFILE_LICENSE)) cur->attrFlags |= RPMFILE_SPECIALDIR; } argvAdd(fileNames, s); @@ -1708,9 +1709,10 @@ exit: return rc; } -static char * getSpecialDocDir(Header h) +static char * getSpecialDocDir(Header h, rpmFlags sdtype) { const char *errstr = NULL; + const char *dirtype = (sdtype == RPMFILE_DOC) ? "docdir" : "licensedir"; const char *fmt_default = "%{NAME}-%{VERSION}"; char *fmt_macro = rpmExpand("%{?_docdir_fmt}", NULL); char *fmt = NULL; @@ -1727,19 +1729,21 @@ static char * getSpecialDocDir(Header h) if (fmt == NULL) fmt = headerFormat(h, fmt_default, &errstr); - res = rpmGetPath("%{_docdir}/", fmt, NULL); + res = rpmGetPath("%{_", dirtype, "}/", fmt, NULL); free(fmt); free(fmt_macro); return res; } -static specialDir specialDirNew(Header h, AttrRec ar, AttrRec def_ar) +static specialDir specialDirNew(Header h, rpmFlags sdtype, + AttrRec ar, AttrRec def_ar) { specialDir sd = xcalloc(1, sizeof(*sd)); dupAttrRec(ar, &(sd->ar)); dupAttrRec(def_ar, &(sd->def_ar)); - sd->dirname = getSpecialDocDir(h); + sd->dirname = getSpecialDocDir(h, sdtype); + sd->sdtype = sdtype; return sd; } @@ -1755,25 +1759,30 @@ static specialDir specialDirFree(specialDir sd) return NULL; } -static void processSpecialDocs(rpmSpec spec, Package pkg, FileList fl, +static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl, specialDir sd, int install, int test) { - char *mkdocdir = rpmExpand("%{__mkdir_p} $DOCDIR", NULL); + const char *sdenv = (sd->sdtype == RPMFILE_DOC) ? "DOCDIR" : "LICENSEDIR"; + const char *sdname = (sd->sdtype == RPMFILE_DOC) ? "%doc" : "%license"; + char *mkdocdir = rpmExpand("%{__mkdir_p} $", sdenv, NULL); StringBuf docScript = newStringBuf(); - appendStringBuf(docScript, "DOCDIR=$RPM_BUILD_ROOT"); + appendStringBuf(docScript, sdenv); + appendStringBuf(docScript, "=$RPM_BUILD_ROOT"); appendLineStringBuf(docScript, sd->dirname); - appendLineStringBuf(docScript, "export DOCDIR"); + appendStringBuf(docScript, "export "); + appendLineStringBuf(docScript, sdenv); appendLineStringBuf(docScript, mkdocdir); for (ARGV_const_t fn = sd->files; fn && *fn; fn++) { appendStringBuf(docScript, "cp -pr "); appendStringBuf(docScript, *fn); - appendLineStringBuf(docScript, " $DOCDIR"); + appendStringBuf(docScript, " $"); + appendLineStringBuf(docScript, sdenv); } if (install) { - rpmRC rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", + rpmRC rc = doScript(spec, RPMBUILD_STRINGBUF, sdname, getStringBuf(docScript), test); if (rc && rpmExpandNumeric("%{?_missing_doc_files_terminate_build}")) @@ -1800,6 +1809,7 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, struct FileList_s fl; ARGV_t fileNames = NULL; specialDir specialDoc = NULL; + specialDir specialLic = NULL; pkg->cpioList = NULL; @@ -1853,20 +1863,28 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, for (ARGV_const_t fn = fileNames; fn && *fn; fn++) { if (fl.cur.attrFlags & RPMFILE_SPECIALDIR) { - int oa = (fl.cur.attrFlags & ~(RPMFILE_DOC|RPMFILE_SPECIALDIR)); - if (oa || **fn == '/') { + rpmFlags oattrs = (fl.cur.attrFlags & ~RPMFILE_SPECIALDIR); + specialDir *sdp = NULL; + if (oattrs == RPMFILE_DOC) { + sdp = &specialDoc; + } else if (oattrs == RPMFILE_LICENSE) { + sdp = &specialLic; + } + + if (sdp == NULL || **fn == '/') { rpmlog(RPMLOG_ERR, - _("Can't mix special %%doc with other forms: %s\n"),*fn); + _("Can't mix special %s with other forms: %s\n"), + (oattrs & RPMFILE_DOC) ? "%doc" : "%license", *fn); fl.processingFailed = 1; continue; } - /* save attributes on first special doc for later use */ - if (specialDoc == NULL) { - specialDoc = specialDirNew(pkg->header, - &fl.cur.ar, &fl.def.ar); + /* save attributes on first special doc/license for later use */ + if (*sdp == NULL) { + *sdp = specialDirNew(pkg->header, oattrs, + &fl.cur.ar, &fl.def.ar); } - argvAdd(&specialDoc->files, *fn); + argvAdd(&(*sdp)->files, *fn); continue; } @@ -1892,9 +1910,11 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, fl.haveCaps = 1; } - /* Now process special doc, if there is one */ + /* Now process special docs and licenses if present */ if (specialDoc) - processSpecialDocs(spec, pkg, &fl, specialDoc, installSpecialDoc, test); + processSpecialDir(spec, pkg, &fl, specialDoc, installSpecialDoc, test); + if (specialLic) + processSpecialDir(spec, pkg, &fl, specialLic, installSpecialDoc, test); if (fl.processingFailed) goto exit; @@ -1909,6 +1929,7 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, exit: FileListFree(&fl); specialDirFree(specialDoc); + specialDirFree(specialLic); return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK; } diff --git a/build/parseSpec.c b/build/parseSpec.c index d1a0788db..742059177 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -571,6 +571,7 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags, spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL); } addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC); + addMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC); spec->recursing = recursing; spec->flags = flags; diff --git a/macros.in b/macros.in index 0bf0fa4f9..e06146dbd 100644 --- a/macros.in +++ b/macros.in @@ -197,6 +197,7 @@ package or when debugging this package.\ %{nil} %_defaultdocdir %{_datadir}/doc +%_defaultlicensedir %{_datadir}/licenses # The path to the gzip executable (legacy, use %{__gzip} instead). %_gzipbin %{__gzip}