aboutsummaryrefslogtreecommitdiffstats
path: root/gendepslist2.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gendepslist2.cc')
-rw-r--r--gendepslist2.cc348
1 files changed, 348 insertions, 0 deletions
diff --git a/gendepslist2.cc b/gendepslist2.cc
new file mode 100644
index 0000000..faaf953
--- /dev/null
+++ b/gendepslist2.cc
@@ -0,0 +1,348 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <rpm/rpmlib.h>
+#include <rpm/header.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <fstream>
+#include <algorithm>
+
+#define COMPATIBILITY
+
+string put_first = "filesystem setup";
+
+
+/********************************************************************************/
+/* C++ template functions *******************************************************/
+/********************************************************************************/
+template<class V, class C> 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<string> split(char sep, const string &l) {
+ vector<string> 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<class A, class B> void map_insert(map<A, set<B> > &m, const A &a, const B &b) {
+ if (m.find(a) == m.end()) m[a] = *(new set<B>);
+ m[a].insert(b);
+}
+
+template<class A> bool in(const A &a, const vector<A> &v) {
+ vector<A>::const_iterator p;
+ for (p = v.begin(); p != v.end(); p++) if (*p == a) return 1;
+ return 0;
+}
+template<class A, class B> bool in(const A &a, const map<A,B> &m) {
+ return m.find(a) != m.end();
+}
+
+template<class A, class B> map<A,B> &set2map(const set<A> &s) {
+ map<A,B> map;
+ set<A>::const_iterator p;
+ for (p = s.begin(); p != s.end(); p++) map[*p] = *(new B);
+ return map;
+}
+
+template<class A, class B> void add(set<A> &v1, const B &v2) {
+ typename B::const_iterator p;
+ for (p = v2.begin(); p != v2.end(); p++) v1.insert(*p);
+}
+template<class A, class B> void add(vector<A> &v1, const B &v2) {
+ typename B::const_iterator p;
+ for (p = v2.begin(); p != v2.end(); p++) v1.push_back(*p);
+}
+
+typedef vector<string>::iterator ITv;
+typedef set<string>::iterator ITs;
+typedef map<string, set<string> >::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<string> get_info(Header header, int_32 tag) {
+ int_32 type, count, i;
+ vector<string> 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<string> get_files(Header header) {
+ int_32 type, count, i;
+ char ** baseNames, ** dirNames;
+ int_32 * dirIndexes;
+
+#ifdef COMPATIBILITY
+ // deprecated one
+ vector<string> r = get_info(header, RPMTAG_OLDFILENAMES);
+#else
+ vector<string> 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<string> packages;
+map<string, int> sizes;
+map<string, string> name2fullname;
+map<string, vector<string> > requires, frequires;
+map<string, vector<string> > provided_by, fprovided_by;
+
+void getRequires(FD_t fd) {
+ set<string> 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<string> 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<string>);
+ for (ITs p = all_frequires.begin(); p != all_frequires.end(); p++) fprovided_by[*p] = *(new vector<string>);
+}
+
+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<string> 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<string> 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<string> getDep_(const string &dep, vector<string> &l) {
+ set<string> 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<string> getDep(const string &name) {
+ set<string> 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<string, set<string> > closure(const map<string, set<string> > &names) {
+ map<string, set<string> > r = names;
+
+ map<string, set<string> > reverse;
+ for (ITv i = packages.begin(); i != packages.end(); i++) reverse[*i] = *(new set<string>);
+
+ 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<string> 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<string,string,bool> {
+// 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<string, set<string> > names;
+ for (ITv p = packages.begin(); p != packages.end(); p++) {
+ set<string> s = getDep(*p);
+ s.erase(*p);
+ names[*p] = s;
+ if (out1) *out1 << *p << " " << sizes[*p] << " " << sum(s, (string) " ") << "\n";
+ }
+ if (out2 == 0) return;
+
+ map<string, set<string> > closed = closure(names);
+ for (ITms p = closed.begin(); p != closed.end(); p++) p->second.erase(p->first);
+
+ names = closed;
+ map<string,int> 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<string> put_first_ = split(' ', put_first);
+ vector<string> 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<string,int> 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<string> dep = closed[*p];
+ *out2 << *p << " " << sizes[*p];
+ for (ITs q = dep.begin(); q != dep.end(); q++) {
+ if (q->find('|') >= 0) {
+ vector<string> 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 <depslist>] 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;
+}