#include #include #include #include #include #include #include #include #include #include #include #define COMPATIBILITY /********************************************************************************/ /* 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)); 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 set &m) { return m.find(a) != m.end(); } 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 ******************************************************************/ /********************************************************************************/ int nb_hdlists; vector packages; map sizes; map > hdlist2names; map name2fullname; map > requires, frequires; map > provided_by, fprovided_by; void getRequires(FD_t fd, int current_hdlist) { 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); if (in(s_name, name2fullname)) continue; packages.push_back(name); name2fullname[s_name] = name; hdlist2names[current_hdlist].insert(name); sizes[name] = get_int(header, RPMTAG_SIZE); 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); } bool notfound(const string &s) { return strncmp(s.c_str(), "NOTFOUND_", sizeof("NOTFOUND_") - 1) == 0; } void getProvides(FD_t fd, int current_hdlist) { map used; 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); if (in(s_name, used)) continue; used[s_name] = true; 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; // } //}; inline int verif(int npack, int ndep, const string &package, const string &dep) { if (ndep > npack) cerr << package << " requires " << dep << " which is not in the same hdlist " << ndep << " > " << npack << "\n"; return ndep; } 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; vector packages; set list = hdlist2names[0]; int nb2hdlist[2 * names.size()]; // the 2x is a hacky hack. nb_names is not enough, need a little more int i = 0; string n; map nb_deps_done; for (ITms p = names.begin(); p != names.end(); p++) nb_deps_done[p->first] = 0; for (int i = -1, nb = 0; i < nb_hdlists; i++, nb++) { set list; if (i == -1) { list.insert(name2fullname["filesystem"]); nb_deps_done[name2fullname["filesystem"]] = 10; list.insert(name2fullname["setup"]); nb_deps_done[name2fullname["setup"]] = 10; add(list, names[name2fullname["basesystem"]]); list.insert(name2fullname["basesystem"]); for (ITs p = list.begin(); p != list.end(); p++) { if (p->find('|') != string::npos) { list.erase(*p); vector l = split('|', *p); for (ITv k = l.begin(); k != l.end(); k++) { list.insert(*k); add(list, names[*k]); } } } for (ITs p = list.begin(); p != list.end(); p++) { hdlist2names[0].erase(*p); if (p->find('|') != string::npos) list.erase(*p); } } else { list = hdlist2names[i]; } while (list.begin() != list.end()) { int l_best = 9999; for (ITs p = list.begin(); p != list.end(); p++) { if (notfound(*p)) { list.erase(*p); continue; } int lo = names[*p].size() - nb_deps_done[*p]; if (lo < l_best) { l_best = lo; n = *p; if (l_best == -1) break; } } names.erase(n); list.erase(n); nb2hdlist[nb++] = i; packages.push_back(n); for (ITms p = names.begin(); p != names.end(); p++) p->second.erase(n); } } cerr << "ordering done\n"; 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('|') != string::npos) { vector l = split('|', *q); int skip = 0; for (ITv k = l.begin(); k != l.end(); k++) if (*p == *k) { skip = 1; break; } if (skip) continue; *out2 << " "; int previous = 0; for (ITv k = l.begin(); k != l.end(); k++) { if (previous) *out2 << "|"; previous = 1; verif(nb2hdlist[i], nb2hdlist[where[*k]], *p, *k); *out2 << where[*k]; } } else if (notfound(*q)) { *out2 << " " << *q; } else { verif(nb2hdlist[i], nb2hdlist[where[*q]], *p, *q); *out2 << " " << where[*q]; } } *out2 << "\n"; } } void hdlists(void (*f)(FD_t, int), const char *file, int current_hdlist) { bool isfile = strlen(file) > 4 && strncmp(file + strlen(file) - 4, ".rpm", 4) == 0; string cmd = isfile ? "rpm2header " : "bzip2 -d <"; FILE *pipe = popen((cmd + file + " 2>/dev/null").c_str(), "r"); f(fdDup(fileno(pipe)), current_hdlist); if (fclose(pipe) != 0) { cerr << "bad hdlist " << file << "\n"; exit(1); } } 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; } nb_hdlists = argc - 1; for (int i = 1; i < argc; i++) if ((string)argv[i] == "--") break; else hdlists(getRequires, argv[i], i - 1); cerr << "getRequires done\n"; for (int i = 1; i < argc; i++) if ((string)argv[i] == "--") continue; else hdlists(getProvides, argv[i], i - 1); cerr << "getProvides done\n"; printDepslist(out1, out2); delete out1; delete out2; }