genpkglist: don't strip paths that are owned by 2 or more packages

Another attempt to deal with semi-unmet dependencies.  This should fix
most of the cross-arch semi-unmets generated via conetnts_index_all.

Consider a few noarch packages which own /usr/share/foo.  Now if i586
package somehow refers /usr/share/foo, contents_index_all search will
produce as-is reference, which is going to be cross-arch semi-unmet.

Note that if /usr/share/foo is owned by only one package,
contents_index_all search will produce explicit package name.

This is why genpkglist should not strip paths that are owned
by 2 or more packages.
This commit is contained in:
Alexey Tourbin 2007-10-08 22:33:47 +04:00
parent 341bcecf1e
commit bb7eaffe62

View File

@ -1,5 +1,5 @@
--- apt-0.5.15lorg2/tools/genpkglist.cc- 2007-08-11 21:39:13 +0400
+++ apt-0.5.15lorg2/tools/genpkglist.cc 2007-08-11 21:47:17 +0400
--- apt-0.5.15lorg2/tools/genpkglist.cc- 2007-10-08 03:24:54 +0400
+++ apt-0.5.15lorg2/tools/genpkglist.cc 2007-10-08 22:29:14 +0400
@@ -18,6 +18,8 @@
#include <map>
#include <iostream>
@ -9,14 +9,17 @@
#include <apt-pkg/error.h>
#include <apt-pkg/tagfile.h>
#include <apt-pkg/configuration.h>
@@ -77,20 +79,30 @@ typedef struct {
@@ -77,20 +79,99 @@ typedef struct {
string url;
} UpdateInfo;
+static std::tr1::unordered_set<std::string> reqfiles;
+// path-like Requires
+static
+std::tr1::unordered_set<std::string> reqfiles;
-static inline int usefullFile(char *a)
+static int usefulFile(const char *dir, const char *basename)
+static
+void addRequiredPath(const char *str)
{
- int l = strlen(a);
-
@ -25,7 +28,71 @@
-
- if (l < 3)
- return 0;
+ if (strstr(dir, "bin/"))
+ reqfiles.insert(str);
+}
+
+static
+bool isRequiredPath(const char *dir, const char *basename)
+{
+ char fullname[strlen(dir) + strlen(basename) + 1];
+ strcpy(fullname, dir);
+ strcat(fullname, basename);
+ if (reqfiles.find(fullname) != reqfiles.end())
+ return true;
+ return false;
+}
+
+// atoms are constant strings with fixed address
+static
+std::tr1::unordered_set<std::string> atoms;
+
+static
+const char *atom(const char *str)
+{
+ return atoms.insert(str).first->c_str();
+}
+
+// memory-efficient way to map path -> packages:
+// dir -> <basename -> pkg+>
+typedef std::multimap<const char * /* basename */, const char * /* pkg */> BPM;
+static
+std::map<const char * /* dir */, BPM> pathOwners;
+
+typedef BPM::const_iterator BPI;
+
+static
+void addPathOwner(const char *dir, const char *basename, const char *pkg)
+{
+ BPM& bp = pathOwners[atom(dir)];
+ basename = atom(basename);
+ pkg = atom(pkg);
+ // check if pkg is already there
+ std::pair<BPI, BPI> ii = bp.equal_range(basename);
+ for (BPI i = ii.first; i != ii.second; ++i) {
+ if (i->second == pkg) {
+ //fprintf(stderr, "already: %s%s %s\n", dir, basename, pkg);
+ return;
+ }
+ }
+ bp.insert(std::make_pair(basename, pkg));
+}
+
+static
+int countPathOwners(const char *dir, const char *basename)
+{
+ BPM& bp = pathOwners[atom(dir)];
+ basename = atom(basename);
+ std::pair<BPI, BPI> ii = bp.equal_range(basename);
+ return std::distance(ii.first, ii.second);
+}
+
+static
+int usefulFile(const char *dir, const char *basename)
+{
+ // standard dirs
+ if (strstr(dir, "/bin/"))
+ return 1;
+ if (strstr(dir, "/sbin/"))
+ return 1;
+ if (strstr(dir, "/etc/"))
+ return 1;
@ -33,6 +100,7 @@
- if (strcmp(a + l - 3, ".so") == 0
- || strstr(a, ".so."))
- return 1;
+ // libraries
+ const char *pos = strstr(basename, ".so");
+ if (pos > basename) {
+ int c = pos[3];
@ -40,35 +108,40 @@
+ return 1;
+ }
+
+ if (reqfiles.size() > 0) {
+ char fullname[strlen(dir) + strlen(basename) + 1];
+ strcpy(fullname, dir);
+ strcat(fullname, basename);
+ if (reqfiles.find(fullname) != reqfiles.end())
+ return 2;
+ }
+ // if this path is required by any package, it is useful
+ if (isRequiredPath(dir, basename))
+ return 2;
+
+ // if the path is owned by two or more packages, it is still useful
+ if (countPathOwners(dir, basename) > 1)
+ return 3;
+
+ // other paths are not useful
return 0;
}
@@ -133,9 +145,8 @@ static void copyStrippedFileList(Header
@@ -131,11 +212,8 @@ static void copyStrippedFileList(Header
i2 = 0;
for (i = 0; i < count2 ; i++)
{
int ok = 0;
- int ok = 0;
-
- ok = usefullFile(basenames[i]);
- if (!ok)
- ok = usefullFile(dirnames[dirindexes[i]]);
+ ok = usefulFile(dirnames[dirindexes[i]], basenames[i]);
+ // if (ok > 1) cerr << "useful file: " << dirnames[dirindexes[i]] << basenames[i] <<endl;
+ int ok = usefulFile(dirnames[dirindexes[i]], basenames[i]);
+ // if (ok > 1) cerr << "useful(" << ok <<"): " << dirnames[dirindexes[i]] << basenames[i] << std::endl;
if (!ok) {
int k = i;
@@ -599,6 +610,50 @@ int main(int argc, char ** argv)
@@ -599,6 +677,76 @@ int main(int argc, char ** argv)
int isSource;
#endif
+ if (!fullFileList) {
+ // first pass: initialize reqfiles
+ // ALT: file list cannot be stripped in a dumb manner -- this is going
+ // to produce unmet dependencies. First pass is required to initialize
+ // certain data structures.
+ for (entry_cur = 0; entry_cur < entry_no; entry_cur++) {
+ if (progressBar) {
+ if (entry_cur)
@ -89,9 +162,10 @@
+ rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
+ if (rc == 0) {
+#endif
+ int reqtype;
+ const char **requires;
+ int nreq;
+ // path-like Requires
+ int_32 reqtype = 0;
+ const char **requires = NULL;
+ int_32 nreq = 0;
+ rc = headerGetEntry(h, RPMTAG_REQUIRENAME, &reqtype, (void**)&requires, &nreq);
+ if (rc == 1) {
+ if (reqtype == RPM_STRING_ARRAY_TYPE) {
@ -100,12 +174,35 @@
+ const char *req = requires[i];
+ if (*req == '/') {
+ // cerr << dirEntries[entry_cur]->d_name << " requires " << req << endl;
+ reqfiles.insert(req);
+ addRequiredPath(req);
+ }
+ }
+ }
+ headerFreeTag(h, requires, (rpmTagType)reqtype);
+ }
+ headerFreeTag(h, requires, (rpmTagType)reqtype);
+
+ // path ownership
+ const char *pkg = NULL;
+ int_32 pkgt = 0;
+ const char **bn = NULL, **dn = NULL;
+ int_32 *di = NULL;
+ int_32 bnt = 0, dnt = 0, dit = 0;
+ int_32 bnc = 0;
+ rc = headerGetEntry(h, RPMTAG_NAME, &pkgt, (void**)&pkg, NULL)
+ && headerGetEntry(h, RPMTAG_BASENAMES, &bnt, (void**)&bn, &bnc)
+ && headerGetEntry(h, RPMTAG_DIRNAMES, &dnt, (void**)&dn, NULL)
+ && headerGetEntry(h, RPMTAG_DIRINDEXES, &dit, (void**)&di, NULL)
+ ;
+ if (rc == 1) {
+ int i;
+ for (i = 0; i < bnc; i++)
+ addPathOwner(dn[di[i]], bn[i], pkg);
+ }
+ headerFreeTag(h, pkg, (rpmTagType)pkgt);
+ headerFreeTag(h, bn, (rpmTagType)bnt);
+ headerFreeTag(h, dn, (rpmTagType)dnt);
+ headerFreeTag(h, di, (rpmTagType)dit);
+
+ headerFree(h);
+ }
+ Fclose(fd);