summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2010-03-23 16:21:27 +0200
committerPanu Matilainen <pmatilai@redhat.com>2010-03-23 16:32:46 +0200
commit8c7e53ec80e84f48bfc67181f3d5dd81ecdb7523 (patch)
tree1777f57f13aaa83b3e1c77ba66f2d8e29547e8e1
parent7628c31bb9688c04561bd46c840ec9437fab4f67 (diff)
downloadlibrpm-tizen-8c7e53ec80e84f48bfc67181f3d5dd81ecdb7523.tar.gz
librpm-tizen-8c7e53ec80e84f48bfc67181f3d5dd81ecdb7523.tar.bz2
librpm-tizen-8c7e53ec80e84f48bfc67181f3d5dd81ecdb7523.zip
First take at pluggable file attribute + dependency extraction system
- move most of the hardwired classification logic from rpmfc C-code to macro-based configuration, supporting drop-in addition of arbitrary new attributes + dependency extractors based on regex matching of libmagic file types and paths - just the initial rough conversion of our built-in dependency types, various open questions + todo-items remain, plus likely fair amount of more-or-less subtle breakage
-rw-r--r--Makefile.am4
-rw-r--r--build/rpmfc.c331
-rw-r--r--configure.ac2
-rw-r--r--fileattrs/Makefile.am11
-rw-r--r--fileattrs/desktop2
-rw-r--r--fileattrs/elf4
-rw-r--r--fileattrs/font3
-rw-r--r--fileattrs/libtool3
-rw-r--r--fileattrs/mono3
-rw-r--r--fileattrs/ocaml3
-rw-r--r--fileattrs/perl3
-rw-r--r--fileattrs/perllib3
-rw-r--r--fileattrs/pkgconfig3
-rw-r--r--fileattrs/python4
-rw-r--r--fileattrs/script3
-rw-r--r--lib/rpmrc.c1
-rw-r--r--macros.in56
17 files changed, 223 insertions, 216 deletions
diff --git a/Makefile.am b/Makefile.am
index 1000648ff..6cd0bdd8d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,9 +19,9 @@ endif
if WITH_LUAEXT
SUBDIRS += luaext
endif
-SUBDIRS += rpmio lib build python scripts doc . tests
+SUBDIRS += rpmio lib build python scripts fileattrs doc . tests
-DIST_SUBDIRS = po misc luaext rpmio lib build python scripts doc tests
+DIST_SUBDIRS = po misc luaext rpmio lib build python scripts fileattrs doc tests
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/build/rpmfc.c b/build/rpmfc.c
index 29f58d1b6..af67ad3b5 100644
--- a/build/rpmfc.c
+++ b/build/rpmfc.c
@@ -19,6 +19,13 @@
#include "debug.h"
+typedef struct rpmfcAttr_s {
+ char *name;
+ regex_t *pattern;
+ regex_t *magic;
+ int exeonly;
+} * rpmfcAttr;
+
/**
*/
struct rpmfc_s {
@@ -31,6 +38,8 @@ struct rpmfc_s {
int tracked; /*!< Versioned Provides: tracking dependency added? */
size_t brlen; /*!< strlen(spec->buildRoot) */
+ rpmfcAttr *atypes; /*!< known file attribute types */
+
ARGV_t fn; /*!< (no. files) file names */
ARGV_t *fattrs; /*!< (no. files) file attribute tokens */
ARGI_t fcolor; /*!< (no. files) file colors */
@@ -45,14 +54,64 @@ struct rpmfc_s {
rpmds requires; /*!< (no. requires) package requires */
};
-/**
- */
struct rpmfcTokens_s {
const char * token;
rpm_color_t colors;
- const char * attrs;
};
+static char *rpmfcAttrMacro(const char *name, const char *attr)
+{
+ char *macro = rpmExpand("%{?__", name, "_", attr, "}", NULL);
+ return rstreq(macro, "") ? rfree(macro) : macro;
+}
+
+static regex_t *rpmfcAttrReg(const char *name, const char *attr)
+{
+ regex_t *reg = NULL;
+ char *pattern = rpmfcAttrMacro(name, attr);
+ if (pattern) {
+ reg = rcalloc(1, sizeof(*reg));
+ if (regcomp(reg, pattern, REG_EXTENDED) != 0) {
+ rpmlog(RPMLOG_WARNING, _("Ignoring invalid regex %s\n"), pattern);
+ reg = rfree(reg);
+ }
+ rfree(pattern);
+ }
+ return reg;
+}
+
+static rpmfcAttr rpmfcAttrNew(const char *name)
+{
+ rpmfcAttr attr = xcalloc(1, sizeof(*attr));
+
+ char *eom = rpmfcAttrMacro(name, "exeonly");
+ attr->exeonly = rpmExpandNumeric(eom);
+ free(eom);
+
+ attr->name = xstrdup(name);
+ attr->pattern = rpmfcAttrReg(name, "pattern");
+ attr->magic = rpmfcAttrReg(name, "magic");
+
+ return attr;
+}
+
+static rpmfcAttr rpmfcAttrFree(rpmfcAttr attr)
+{
+ if (attr) {
+ if (attr->pattern) {
+ regfree(attr->pattern);
+ rfree(attr->pattern);
+ }
+ if (attr->magic) {
+ regfree(attr->magic);
+ rfree(attr->magic);
+ }
+ rfree(attr->name);
+ rfree(attr);
+ }
+ return NULL;
+}
+
/**
*/
static int rpmfcExpandAppend(ARGV_t * argvp, ARGV_const_t av)
@@ -420,118 +479,53 @@ assert(EVR != NULL);
return 0;
}
-typedef enum depTypes_e {
- DEP_NONE = 0,
- DEP_REQ = (1 << 0),
- DEP_PROV = (1 << 1),
-} depTypes;
-
-/* Handle RPMFC_INCLUDE "stop signal" as an attribute? */
+/* Only used for elf coloring and controlling RPMTAG_FILECLASS inclusion now */
static const struct rpmfcTokens_s const rpmfcTokens[] = {
- { "directory", RPMFC_INCLUDE, "directory" },
-
- { " shared object", RPMFC_BLACK, "library" },
- { " executable", RPMFC_BLACK, "executable" },
- { " statically linked", RPMFC_BLACK, "static" },
- { " not stripped", RPMFC_BLACK, "notstripped" },
- { " archive", RPMFC_BLACK, "archive" },
-
- { "ELF 32-bit", RPMFC_ELF32|RPMFC_INCLUDE, "elf" },
- { "ELF 64-bit", RPMFC_ELF64|RPMFC_INCLUDE, "elf" },
-
- /* "foo script text" is a file with shebang interpreter directive */
- { " script text", RPMFC_BLACK, "script" },
- { " document", RPMFC_BLACK, "document" },
-
- { " compressed", RPMFC_BLACK, "compressed" },
-
- { "troff or preprocessor input", RPMFC_INCLUDE, "man" },
- { "GNU Info", RPMFC_INCLUDE, "info" },
+ { "directory", RPMFC_INCLUDE },
- { "perl ", RPMFC_INCLUDE, "perl" },
- { "Perl5 module source text", RPMFC_INCLUDE, "perl,module" },
+ { "ELF 32-bit", RPMFC_ELF32|RPMFC_INCLUDE },
+ { "ELF 64-bit", RPMFC_ELF64|RPMFC_INCLUDE },
- /* XXX "a /usr/bin/python -t script text executable" */
- /* XXX "python 2.3 byte-compiled" */
- { "python ", RPMFC_INCLUDE, "python" },
+ { "troff or preprocessor input", RPMFC_INCLUDE },
+ { "GNU Info", RPMFC_INCLUDE },
- { "libtool library ", RPMFC_INCLUDE, "libtool" },
- { "pkgconfig ", RPMFC_INCLUDE, "pkgconfig" },
+ { "perl ", RPMFC_INCLUDE },
+ { "Perl5 module source text", RPMFC_INCLUDE },
+ { "python ", RPMFC_INCLUDE },
- { "Objective caml ", RPMFC_INCLUDE, "ocaml" },
+ { "libtool library ", RPMFC_INCLUDE },
+ { "pkgconfig ", RPMFC_INCLUDE },
- /* XXX .NET executables and libraries. file(1) cannot differ from win32
- * executables unfortunately :( */
- { "Mono/.Net assembly", RPMFC_INCLUDE, "mono" },
+ { "Objective caml ", RPMFC_INCLUDE },
+ { "Mono/.Net assembly", RPMFC_INCLUDE },
- { "current ar archive", RPMFC_INCLUDE, "static,library,archive" },
+ { "current ar archive", RPMFC_INCLUDE },
+ { "Zip archive data", RPMFC_INCLUDE },
+ { "tar archive", RPMFC_INCLUDE },
+ { "cpio archive", RPMFC_INCLUDE },
+ { "RPM v3", RPMFC_INCLUDE },
+ { "RPM v4", RPMFC_INCLUDE },
- { "Zip archive data", RPMFC_INCLUDE, "compressed,archive" },
- { "tar archive", RPMFC_INCLUDE, "archive" },
- { "cpio archive", RPMFC_INCLUDE, "archive" },
- { "RPM v3", RPMFC_INCLUDE, "archive" },
- { "RPM v4", RPMFC_INCLUDE, "archive" },
+ { " image", RPMFC_INCLUDE },
+ { " font", RPMFC_INCLUDE },
+ { " Font", RPMFC_INCLUDE },
- { " image", RPMFC_INCLUDE, "image" },
- { " font metrics", RPMFC_WHITE|RPMFC_INCLUDE, NULL },
- { " font", RPMFC_INCLUDE, "font" },
- { " Font", RPMFC_INCLUDE, "font" },
+ { " commands", RPMFC_INCLUDE },
+ { " script", RPMFC_INCLUDE },
- { " commands", RPMFC_INCLUDE, "script" },
- { " script", RPMFC_INCLUDE, "script" },
+ { "empty", RPMFC_INCLUDE },
- { "empty", RPMFC_INCLUDE, NULL },
+ { "HTML", RPMFC_INCLUDE },
+ { "SGML", RPMFC_INCLUDE },
+ { "XML", RPMFC_INCLUDE },
- { "HTML", RPMFC_INCLUDE, NULL },
- { "SGML", RPMFC_INCLUDE, NULL },
- { "XML", RPMFC_INCLUDE, NULL },
+ { " source", RPMFC_INCLUDE },
+ { "GLS_BINARY_LSB_FIRST", RPMFC_INCLUDE },
+ { " DB ", RPMFC_INCLUDE },
- { " source", RPMFC_INCLUDE, NULL },
- { "GLS_BINARY_LSB_FIRST", RPMFC_INCLUDE, NULL },
- { " DB ", RPMFC_INCLUDE, NULL },
+ { " text", RPMFC_INCLUDE },
- { "symbolic link to", RPMFC_BLACK, "symlink" },
- { "socket", RPMFC_BLACK, "device" }, /* XXX device? */
- { "special", RPMFC_BLACK, "device" },
- { " text", RPMFC_INCLUDE, "text" },
-
- { "ASCII", RPMFC_WHITE, NULL },
- { "ISO-8859", RPMFC_WHITE, NULL },
-
- { "data", RPMFC_WHITE, NULL },
-
- { "application", RPMFC_WHITE, NULL },
- { "boot", RPMFC_WHITE, NULL },
- { "catalog", RPMFC_WHITE, NULL },
- { "code", RPMFC_WHITE, NULL },
- { "file", RPMFC_WHITE, NULL },
- { "format", RPMFC_WHITE, NULL },
- { "message", RPMFC_WHITE, NULL },
- { "program", RPMFC_WHITE, NULL },
-
- { "broken symbolic link to ", RPMFC_WHITE|RPMFC_ERROR, NULL },
- { "can't read", RPMFC_WHITE|RPMFC_ERROR, NULL },
- { "can't stat", RPMFC_WHITE|RPMFC_ERROR, NULL },
- { "executable, can't read", RPMFC_WHITE|RPMFC_ERROR, NULL },
- { "core file", RPMFC_WHITE|RPMFC_ERROR, NULL },
-
- { NULL, RPMFC_BLACK, NULL }
-};
-
-typedef struct rpmfcPathTbl_s {
- const char *pattern;
- const char *attrs;
-} * rpmfcPathTbl;
-
-
-static struct rpmfcPathTbl_s rpmfcPathTable[] = {
- { "^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so)$",
- "python" },
- { "^%{_bindir}/python[[:digit:]]\\.[[:digit:]]$",
- "python" },
- { "^%{_datadir}/.*/.*\\.desktop$",
- "desktop" },
- { NULL, NULL },
+ { NULL, RPMFC_BLACK }
};
static void argvAddTokens(ARGV_t *argv, const char *tnames)
@@ -545,25 +539,36 @@ static void argvAddTokens(ARGV_t *argv, const char *tnames)
}
}
-static void rpmfcPathAttributes(const char *path, ARGV_t *attrs)
+static int regMatch(regex_t *reg, const char *val)
{
- for (rpmfcPathTbl pcat = rpmfcPathTable; pcat->pattern; pcat++) {
- char *pattern = rpmExpand(pcat->pattern, NULL);
- regex_t reg;
- if (regcomp(&reg, pattern, REG_EXTENDED)) {
- rpmlog(RPMLOG_WARNING, _("Ignoring invalid regex: %s\n"), pattern);
- } else {
- if (regexec(&reg, path, 0, NULL, 0) == 0) {
- argvAddTokens(attrs, pcat->attrs);
- }
- regfree(&reg);
- }
- free(pattern);
+ return (reg && regexec(reg, val, 0, NULL, 0) == 0);
+}
+
+static void rpmfcAttributes(rpmfc fc, const char *ftype, const char *fullpath)
+{
+ const char *path = fullpath + fc->brlen;
+ int is_executable = 0;
+ struct stat st;
+ if (stat(fullpath, &st) == 0) {
+ is_executable = (S_ISREG(st.st_mode)) &&
+ (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
+ }
+
+ for (rpmfcAttr *attr = fc->atypes; attr && *attr; attr++) {
+ /* Filter out by file modes if set */
+ if ((*attr)->exeonly && !is_executable)
+ continue;
+
+ /* Add attributes on libmagic type & path pattern matches */
+ if (regMatch((*attr)->magic, ftype))
+ argvAddTokens(&fc->fattrs[fc->ix], (*attr)->name);
+ if (regMatch((*attr)->pattern, path))
+ argvAddTokens(&fc->fattrs[fc->ix], (*attr)->name);
}
}
-/* Return attribute tokens + color for a given libmagic classification string */
-static void rpmfcAttributes(const char * fmstr, ARGV_t *attrs, int *color)
+/* Return color for a given libmagic classification string */
+static rpm_color_t rpmfcColor(const char * fmstr)
{
rpmfcToken fct;
rpm_color_t fcolor = RPMFC_BLACK;
@@ -572,14 +577,12 @@ static void rpmfcAttributes(const char * fmstr, ARGV_t *attrs, int *color)
if (strstr(fmstr, fct->token) == NULL)
continue;
- argvAddTokens(attrs, fct->attrs);
-
fcolor |= fct->colors;
if (fcolor & RPMFC_INCLUDE)
break;
}
- if (color) *color |= fcolor;
+ return fcolor;
}
void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
@@ -670,6 +673,9 @@ assert(ix < nrequires);
rpmfc rpmfcFree(rpmfc fc)
{
if (fc) {
+ for (rpmfcAttr *attr = fc->atypes; attr && *attr; attr++)
+ rpmfcAttrFree(*attr);
+ rfree(fc->atypes);
fc->fn = argvFree(fc->fn);
for (int i = 0; i < fc->nfiles; i++)
argvFree(fc->fattrs[i]);
@@ -705,57 +711,6 @@ rpmds rpmfcRequires(rpmfc fc)
return (fc != NULL ? fc->requires : NULL);
}
-static int isExecutable(const char *fn)
-{
- struct stat st;
- if (stat(fn, &st) < 0)
- return -1;
- return (S_ISREG(st.st_mode) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)));
-}
-
-/**
- * Extract dependencies for a given attribute.
- * @param fc file classifier
- * @param attr attribute name
- * @return 0 on success
- */
-static int rpmfcAttrDeps(rpmfc fc, const char *attr)
-{
- const char * fn = fc->fn[fc->ix];
- ARGV_t fattrs = fc->fattrs[fc->ix];
- int is_executable = isExecutable(fn);
- depTypes types = DEP_NONE;
- int rc = 0;
-
- if (is_executable < 0)
- return -1;
-
- /* TODO: generalize this logic into classification attributes */
- if (rstreq(attr, "script")) {
- if (is_executable)
- types |= DEP_REQ;
- } else if (rstreq(attr, "perl")) {
- if (hasAttr(fattrs, "module"))
- types |= (DEP_REQ|DEP_PROV);
- if (is_executable)
- types |= DEP_REQ;
- } else if (rstreq(attr, "mono")) {
- types = DEP_PROV;
- if (is_executable)
- types |= DEP_REQ;
- } else {
- types = (DEP_REQ|DEP_PROV);
- }
-
- if (types & DEP_PROV)
- rc += rpmfcHelper(fc, 'P', attr);
- if (types & DEP_REQ)
- rc += rpmfcHelper(fc, 'R', attr);
-
- return rc;
-}
-
-
rpmRC rpmfcApply(rpmfc fc)
{
const char * s;
@@ -776,7 +731,8 @@ rpmRC rpmfcApply(rpmfc fc)
/* Generate package and per-file dependencies. */
for (fc->ix = 0; fc->fn[fc->ix] != NULL; fc->ix++) {
for (ARGV_t fattr = fc->fattrs[fc->ix]; fattr && *fattr; fattr++) {
- xx = rpmfcAttrDeps(fc, *fattr);
+ xx += rpmfcHelper(fc, 'P', *fattr);
+ xx += rpmfcHelper(fc, 'R', *fattr);
}
}
@@ -843,6 +799,26 @@ assert(dix >= 0);
return RPMRC_OK;
}
+static int initAttrs(rpmfc fc)
+{
+ ARGV_t files = NULL;
+ char * attrPath = rpmExpand("%{_fileattrsdir}/*", NULL);
+ int nattrs = 0;
+
+ /* Discover known attributes from pathnames + initialize them */
+ if (rpmGlob(attrPath, NULL, &files) == 0) {
+ nattrs = argvCount(files);
+ fc->atypes = xcalloc(nattrs + 1, sizeof(*fc->atypes));
+ for (int i = 0; i < nattrs; i++) {
+ fc->atypes[i] = rpmfcAttrNew(basename(files[i]));
+ }
+ fc->atypes[nattrs] = NULL;
+ argvFree(files);
+ }
+ free(attrPath);
+ return nattrs;
+}
+
rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
{
ARGV_t fcav = NULL;
@@ -854,6 +830,11 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
if (fc == NULL || argv == NULL)
return 0; /* XXX looks very wrong */
+ if (initAttrs(fc) < 1) {
+ rpmlog(RPMLOG_ERR, _("No file attributes configured\n"));
+ goto exit;
+ }
+
fc->nfiles = argvCount(argv);
fc->fattrs = xcalloc(fc->nfiles, sizeof(*fc->fattrs));
@@ -934,11 +915,11 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
/* Save the file type string. */
xx = argvAdd(&fcav, ftype);
- /* Add (filtered) file attribute tokens */
- rpmfcAttributes(ftype, &fc->fattrs[fc->ix], &fcolor);
+ /* Add (filtered) file coloring */
+ fcolor |= rpmfcColor(ftype);
- /* Add path-based attributes, strip buildroot for regex sanity */
- rpmfcPathAttributes(s+fc->brlen, &fc->fattrs[fc->ix]);
+ /* Add attributes based on file type and/or path */
+ rpmfcAttributes(fc, ftype, s);
xx = argiAdd(&fc->fcolor, fc->ix, fcolor);
diff --git a/configure.ac b/configure.ac
index 1a6a1924b..a34d9e273 100644
--- a/configure.ac
+++ b/configure.ac
@@ -816,7 +816,7 @@ AC_SUBST([dirstamp],[\${am__leading_dot}dirstamp])
AC_CONFIG_FILES([Makefile
rpmio/Makefile lib/Makefile build/Makefile
- po/Makefile.in scripts/Makefile
+ po/Makefile.in scripts/Makefile fileattrs/Makefile
misc/Makefile
doc/Makefile
python/Makefile
diff --git a/fileattrs/Makefile.am b/fileattrs/Makefile.am
new file mode 100644
index 000000000..379737a4f
--- /dev/null
+++ b/fileattrs/Makefile.am
@@ -0,0 +1,11 @@
+# Makefile for rpm file attributes
+
+include $(top_srcdir)/rpm.am
+
+fattrsdir = $(rpmconfigdir)/fileattrs
+
+fattrs_DATA = \
+ desktop elf font libtool perl perllib pkgconfig python \
+ ocaml script
+
+EXTRA_DIST = $(fattrs_DATA)
diff --git a/fileattrs/desktop b/fileattrs/desktop
new file mode 100644
index 000000000..ff74864cb
--- /dev/null
+++ b/fileattrs/desktop
@@ -0,0 +1,2 @@
+%__desktop_provides %{_rpmconfigdir}/desktop-file.prov
+%__desktop_pattern ^%{_datadir}/applications/.*\\.desktop$
diff --git a/fileattrs/elf b/fileattrs/elf
new file mode 100644
index 000000000..c924dbb7d
--- /dev/null
+++ b/fileattrs/elf
@@ -0,0 +1,4 @@
+%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private}
+%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private}
+%__elf_magic ^ELF (32|64)-bit.*$
+%__elf_exeonly 1
diff --git a/fileattrs/font b/fileattrs/font
new file mode 100644
index 000000000..5c4c78fca
--- /dev/null
+++ b/fileattrs/font
@@ -0,0 +1,3 @@
+%__font_provides %{_rpmconfigdir}/fontconfig.prov
+%__font_requires %{nil}
+%__font_magic ^.* [Ff]ont (program )?(text|data).*$
diff --git a/fileattrs/libtool b/fileattrs/libtool
new file mode 100644
index 000000000..f2ab5e25b
--- /dev/null
+++ b/fileattrs/libtool
@@ -0,0 +1,3 @@
+%__libtool_provides %{_rpmconfigdir}/libtooldeps.sh --provides %{buildroot} %{name}
+%__libtool_requires %{_rpmconfigdir}/libtooldeps.sh --requires %{buildroot} %{name}
+%__libtool_pattern ^%{_libdir}/.*\.la$
diff --git a/fileattrs/mono b/fileattrs/mono
new file mode 100644
index 000000000..d7a908e42
--- /dev/null
+++ b/fileattrs/mono
@@ -0,0 +1,3 @@
+%__mono_provides %{_rpmconfigdir}/mono-find-provides.sh
+%__mono_requires %{_rpmconfigdir}/mono-find-requires.sh
+%__mono_magic ^Mono/.Net assembly.*$
diff --git a/fileattrs/ocaml b/fileattrs/ocaml
new file mode 100644
index 000000000..53b63ae44
--- /dev/null
+++ b/fileattrs/ocaml
@@ -0,0 +1,3 @@
+%__ocaml_provides %{_rpmconfigdir}/ocaml-find-provides.sh
+%__ocaml_requires %{_rpmconfigdir}/ocaml-find-requires.sh
+%__ocaml_magic ^Objective caml.*$
diff --git a/fileattrs/perl b/fileattrs/perl
new file mode 100644
index 000000000..6cb57d17e
--- /dev/null
+++ b/fileattrs/perl
@@ -0,0 +1,3 @@
+%__perl_requires %{_rpmconfigdir}/perl.req
+%__perl_magic ^.*perl .*$
+%__perl_exeonly 1
diff --git a/fileattrs/perllib b/fileattrs/perllib
new file mode 100644
index 000000000..a5e12d453
--- /dev/null
+++ b/fileattrs/perllib
@@ -0,0 +1,3 @@
+%__perlmod_provides %{_rpmconfigdir}/perl.prov
+%__perlmod_requires %{_rpmconfigdir}/perl.req
+%__perlmod_pattern ^/usr/lib(64)?/perl[[:digit:]]/.*\\.pm$
diff --git a/fileattrs/pkgconfig b/fileattrs/pkgconfig
new file mode 100644
index 000000000..f3e00c6cd
--- /dev/null
+++ b/fileattrs/pkgconfig
@@ -0,0 +1,3 @@
+%__pkgconfig_provides %{_rpmconfigdir}/pkgconfigdeps.sh --provides
+%__pkgconfig_requires %{_rpmconfigdir}/pkgconfigdeps.sh --requires
+%__pkgconfig_pattern ^((%{_libdir}|%{_datadir})/pkgconfig/.*\.pc|%{_bindir}/pkg-config)$
diff --git a/fileattrs/python b/fileattrs/python
new file mode 100644
index 000000000..aab7641db
--- /dev/null
+++ b/fileattrs/python
@@ -0,0 +1,4 @@
+%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides
+%__python_requires %{_rpmconfigdir}/pythondeps.sh --requires
+%__python_pattern ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$
+%__python_magic ^python.*(executable|byte-compiled)$
diff --git a/fileattrs/script b/fileattrs/script
new file mode 100644
index 000000000..950113391
--- /dev/null
+++ b/fileattrs/script
@@ -0,0 +1,3 @@
+%__script_requires %{_rpmconfigdir}/script.req
+%__script_magic ^.* script text.*$
+%__script_exeonly 1
diff --git a/lib/rpmrc.c b/lib/rpmrc.c
index 0b752508e..f4be2d5b2 100644
--- a/lib/rpmrc.c
+++ b/lib/rpmrc.c
@@ -430,6 +430,7 @@ static void setDefaults(void)
if (!macrofiles) {
macrofiles = rstrscat(NULL, confdir, "/macros", ":",
confdir, "/platform/%{_target}/macros", ":",
+ confdir, "/fileattrs/*", ":",
confdir, "/" RPMCANONVENDOR "/macros", ":",
SYSCONFDIR "/rpm/macros.*", ":",
SYSCONFDIR "/rpm/macros", ":",
diff --git a/macros.in b/macros.in
index 93cd06346..04c216f33 100644
--- a/macros.in
+++ b/macros.in
@@ -475,44 +475,24 @@ print (t)\
#%__find_conflicts ???
#%__find_obsoletes ???
-#
-# Path to scripts to autogenerate per-filetype package dependencies.
-# If the script supports extra options they can be passed by defining
-# <helper_macro>_opts macro(s), eg in spec:
-# %define __ocaml_requires_opts -i Warnings
-#
-# Note: Used iff _use_internal_dependency_generator is non-zero. The
-# helpers are also used by %{_rpmconfigdir}/rpmdeps {--provides|--requires}.
-#%__perl_provides %{_rpmconfigdir}/perldeps.pl --provides
-#%__perl_requires %{_rpmconfigdir}/perldeps.pl --requires
-
-%__script_requires %{_rpmconfigdir}/script.req
-
-%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private}
-%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private}
-
-%__perl_provides %{_rpmconfigdir}/perl.prov
-%__perl_requires %{_rpmconfigdir}/perl.req
-
-%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides
-%__python_requires %{_rpmconfigdir}/pythondeps.sh --requires
-
-%__mono_provides %{_rpmconfigdir}/mono-find-provides %{_builddir}/%{?buildsubdir} %{buildroot} %{_libdir}
-%__mono_requires %{_rpmconfigdir}/mono-find-requires %{_builddir}/%{?buildsubdir} %{buildroot} %{_libdir}
-
-%__libtool_provides %{_rpmconfigdir}/libtooldeps.sh --provides %{buildroot} %{name}
-%__libtool_requires %{_rpmconfigdir}/libtooldeps.sh --requires %{buildroot} %{name}
-
-%__pkgconfig_provides %{_rpmconfigdir}/pkgconfigdeps.sh --provides
-%__pkgconfig_requires %{_rpmconfigdir}/pkgconfigdeps.sh --requires
-
-%__ocaml_provides %{_rpmconfigdir}/ocaml-find-provides.sh
-%__ocaml_requires %{_rpmconfigdir}/ocaml-find-requires.sh
-
-%__font_provides %{_rpmconfigdir}/fontconfig.prov
-%__font_requires %{nil}
-%__desktop_provides %{_rpmconfigdir}/desktop-file.prov
-%__desktop_requires %{nil}
+#
+# Path to file attribute classifications for automatic dependency
+# extraction, used when _use_internal_dependency_generator
+# is used (on by default). Files can have any number of attributes
+# attached to them, and dependencies are separately extracted for
+# each attribute.
+#
+# To define a new file attribute called "myattr", add a file named
+# "myattr" to this directory, defining the requires and/or provides
+# finder script(s) + magic and/or path pattern regex(es).
+# provides finder and
+# %__myattr_requires path + args to requires finder script for <myattr>
+# %__myattr_provides path + args to provides finder script for <myattr>
+# %__myattr_magic libmagic classification match regex
+# %__myattr_pattern path based classification match regex
+# %__myattr_exeonly require file to be executable to classify
+#
+%_fileattrsdir %{_rpmconfigdir}/fileattrs
#==============================================================================
# ---- Database configuration macros.