#include #include #include #include #include #include #include #include #include #include #include #define COMPATIBILITY string put_first = "filesystem setup"; /********************************************************************************/ /* C++ template functions *******************************************************/ /********************************************************************************/ template C sum(const V &v, const C &join = C()) { typename V::const_iterator p, q; C s = C(); if (v.begin() != v.end()) { for (p = q = v.begin(), q++; q != v.end(); p = q, q++) s += *p + join; s += *p; } return s; } vector split(char sep, const string &l) { vector r; for (int pos = 0, pos2 = 0; pos2 >= 0;) { pos2 = l.find(sep, pos); r.push_back(l.substr(pos, pos2)); pos = pos2 + 1; } return r; } template void map_insert(map > &m, const A &a, const B &b) { if (m.find(a) == m.end()) m[a] = *(new set); m[a].insert(b); } template bool in(const A &a, const vector &v) { vector::const_iterator p; for (p = v.begin(); p != v.end(); p++) if (*p == a) return 1; return 0; } template bool in(const A &a, const map &m) { return m.find(a) != m.end(); } template map &set2map(const set &s) { map map; set::const_iterator p; for (p = s.begin(); p != s.end(); p++) map[*p] = *(new B); return map; } template void add(set &v1, const B &v2) { typename B::const_iterator p; for (p = v2.begin(); p != v2.end(); p++) v1.insert(*p); } template void add(vector &v1, const B &v2) { typename B::const_iterator p; for (p = v2.begin(); p != v2.end(); p++) v1.push_back(*p); } typedef vector::iterator ITv; typedef set::iterator ITs; typedef map >::iterator ITms; /********************************************************************************/ /* header extracting functions **************************************************/ /********************************************************************************/ string get_name(Header header, int_32 tag) { int_32 type, count; char *name; headerGetEntry(header, tag, &type, (void **) &name, &count); return string(name); } int get_int(Header header, int_32 tag) { int_32 type, count; int *i; headerGetEntry(header, tag, &type, (void **) &i, &count); return *i; } vector get_info(Header header, int_32 tag) { int_32 type, count, i; vector r; char **list; headerGetEntry(header, tag, &type, (void **) &list, &count); if (list) { r.reserve(count); for (i = 0; i < count; i++) r.push_back(list[i]); free(list); } return r; } vector get_files(Header header) { int_32 type, count, i; char ** baseNames, ** dirNames; int_32 * dirIndexes; #ifdef COMPATIBILITY // deprecated one vector r = get_info(header, RPMTAG_OLDFILENAMES); #else vector r; #endif headerGetEntry(header, RPMTAG_BASENAMES, &type, (void **) &baseNames, &count); headerGetEntry(header, RPMTAG_DIRINDEXES, &type, (void **) &dirIndexes, NULL); headerGetEntry(header, RPMTAG_DIRNAMES, &type, (void **) &dirNames, NULL); if (baseNames && dirNames && dirIndexes) { r.reserve(count); for(i = 0; i < count; i++) { string s(dirNames[dirIndexes[i]]); s += baseNames[i]; r.push_back(s); } free(baseNames); free(dirNames); } return r; } /********************************************************************************/ /* gendepslist ******************************************************************/ /********************************************************************************/ vector packages; map sizes; map name2fullname; map > requires, frequires; map > provided_by, fprovided_by; void getRequires(FD_t fd) { set all_requires, all_frequires; Header header; while ((header=headerRead(fd, HEADER_MAGIC_YES))) { string s_name = get_name(header, RPMTAG_NAME); string name = s_name + "-" + get_name(header, RPMTAG_VERSION) + "-" + get_name(header, RPMTAG_RELEASE); vector l = get_info(header, RPMTAG_REQUIRENAME); for (ITv p = l.begin(); p != l.end(); p++) { ((*p)[0] == '/' ? frequires : requires)[name].push_back(*p); ((*p)[0] == '/' ? all_frequires : all_requires).insert(*p); } headerFree(header); } for (ITs p = all_requires.begin(); p != all_requires.end(); p++) provided_by[*p] = *(new vector); for (ITs p = all_frequires.begin(); p != all_frequires.end(); p++) fprovided_by[*p] = *(new vector); } void getProvides(FD_t fd) { Header header; while ((header=headerRead(fd, HEADER_MAGIC_YES))) { string s_name = get_name(header, RPMTAG_NAME); string name = s_name + "-" + get_name(header, RPMTAG_VERSION) + "-" + get_name(header, RPMTAG_RELEASE); packages.push_back(name); name2fullname[s_name] = name; sizes[name] = get_int(header, RPMTAG_SIZE); if (in(s_name, provided_by)) provided_by[s_name].push_back(name); vector provides = get_info(header, RPMTAG_PROVIDES); for (ITv p = provides.begin(); p != provides.end(); p++) if (in(*p, provided_by)) provided_by[*p].push_back(name); vector fprovides = get_files(header); for (ITv p = fprovides.begin(); p != fprovides.end(); p++) if (in(*p, fprovided_by)) fprovided_by[*p].push_back(name); headerFree(header); } } set getDep_(const string &dep, vector &l) { set r; switch (l.size()) { case 0: r.insert((string) "NOTFOUND_" + dep); break; case 1: r.insert(l[0]); break; default: r.insert(sum(l, (string)"|")); } return r; } set getDep(const string &name) { set r; r.insert(name); for (ITv p = requires[name].begin(); p != requires[name].end(); p++) add(r, getDep_(*p, provided_by[*p])); for (ITv p = frequires[name].begin(); p != frequires[name].end(); p++) add(r, getDep_(*p, fprovided_by[*p])); return r; } map > closure(const map > &names) { map > r = names; map > reverse; for (ITv i = packages.begin(); i != packages.end(); i++) reverse[*i] = *(new set); for (ITms i = r.begin(); i != r.end(); i++) for (ITs j = i->second.begin(); j != i->second.end(); j++) reverse[*j].insert(i->first); for (ITms i = r.begin(); i != r.end(); i++) { set rev = reverse[i->first]; for (ITs j = rev.begin(); j != rev.end(); j++) { for (ITs k = i->second.begin(); k != i->second.end(); k++) { r[*j].insert(*k); reverse[*k].insert(*j); } } } return r; } //struct cmp : public binary_function { // bool operator()(const string &a, const string &b) { // int na = closed[a].size(); // int nb = closed[b].size(); // return na < nb; // } //}; void printDepslist(ofstream *out1, ofstream *out2) { map > names; for (ITv p = packages.begin(); p != packages.end(); p++) { set s = getDep(*p); s.erase(*p); names[*p] = s; if (out1) *out1 << *p << " " << sizes[*p] << " " << sum(s, (string) " ") << "\n"; } if (out2 == 0) return; map > closed = closure(names); for (ITms p = closed.begin(); p != closed.end(); p++) p->second.erase(p->first); names = closed; map length; for (ITms p = names.begin(); p != names.end(); p++) { int l = p->second.size(); for (ITs q = p->second.begin(); q != p->second.end(); q++) if (q->find('|') >= 0) l += 1000; length[p->first] = l; } vector put_first_ = split(' ', put_first); vector packages; while (names.begin() != names.end()) { string n; unsigned int l_best = 9999; for (ITv p = put_first_.begin(); p != put_first_.end(); p++) if (in(name2fullname[*p], names)) { n = name2fullname[*p]; goto found; } for (ITms p = names.begin(); p != names.end(); p++) if (p->second.size() < l_best) { l_best = p->second.size(); n = p->first; if (l_best == 0) break; } found: names.erase(n); packages.push_back(n); for (ITms p = names.begin(); p != names.end(); p++) p->second.erase(n); } int i = 0; map where; for (ITv p = packages.begin(); p != packages.end(); p++, i++) where[*p] = i; i = 0; for (ITv p = packages.begin(); p != packages.end(); p++, i++) { set dep = closed[*p]; *out2 << *p << " " << sizes[*p]; for (ITs q = dep.begin(); q != dep.end(); q++) { if (q->find('|') >= 0) { vector l = split('|', *q); for (ITv k = l.begin(); k != l.end(); k++) *out2 << " " << where[*k]; } else if (q->compare("NOTFOUND_") > 1) { *out2 << " " << *q; } else { int j = where[*q]; if (j > i) cerr << *p << "\n"; *out2 << " " << j; } } *out2 << "\n"; } } FD_t hdlists(const char *cmd) { return fdDup(fileno(popen(cmd, "r"))); } int main(int argc, char **argv) { ofstream *out1 = 0, *out2 = 0; if (argc > 2 && (string)argv[1] == "-o") { out1 = new ofstream(argv[2]); out2 = new ofstream(((string)argv[2] + ".ordered").c_str()); argc -= 2; argv += 2; } else { out1 = new ofstream(STDOUT_FILENO); } if (argc < 2) { cerr << "usage: gendepslist2 [-o ] hdlists_cz2...\n"; return 1; } string cmd = "bzip2 -dc "; for (int i = 1; i < argc; i++) cmd = cmd + argv[i] + " "; cmd += "2>/dev/null"; getRequires(hdlists(cmd.c_str())); cerr << "getRequires done\n"; getProvides(hdlists(cmd.c_str())); cerr << "getProvides done\n"; printDepslist(out1, out2); delete out1; delete out2; }