steffen: server/utilities/rpmsort main.cpp, NONE, 1.1 rpmsort.pro, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Tue Jul 19 21:29:20 CEST 2005


Author: steffen

Update of /kolabrepository/server/utilities/rpmsort
In directory doto:/tmp/cvs-serv15571/rpmsort

Added Files:
	main.cpp rpmsort.pro 
Log Message:
I needed help with the RPM dependencies. This tool can help a little...

--- NEW FILE: main.cpp ---
/*
 * Helper app to figure out the order which RPMs 
 * must be installed to satisfy dependencies.
 *
 * Uses the 00INDEX.rdf files from OpenPKG
 *
 * (c) 2005 Steffen Hansen <steffen at kdab.net>
 */

#include <QCoreApplication>
#include <QDomElement>
#include <QFile>
#include <QDebug>
#include <QMap>
#include <QSet>
#include <QStringList>

#include <iostream>

struct RPMNode {
  QString name;
  QString about;
  QString version;
  QString release;
  QSet<QString> requires;
  QSet<QString> provides;

  void dumpNode() const {
	std::cout << qPrintable(name) << " [";
	for( QSet<QString>::const_iterator it = requires.constBegin();
		 it != requires.constEnd(); ++it ) {
	  std::cout << " " << qPrintable(*it);
	}
	std::cout << " ]" << std::endl;
  }
};

class RPMSorter {
public:
  void clear();
  bool addFrom( QIODevice* device );

  void dumpNodes() const;
  void dumpNodes( const QMap<QString,RPMNode>& ) const;
  QStringList sort() const;

private:
  QMap<QString,RPMNode> nodes;
};

void RPMSorter::clear()
{
  nodes.clear();
}

bool RPMSorter::addFrom( QIODevice* device ) 
{
  QString errorStr;
  int errorLine;
  int errorColumn;
  QDomDocument domDocument;

  if (!domDocument.setContent(device, true, &errorStr, &errorLine,
							  &errorColumn)) {
	qFatal(	"Parse error at line %d, column %d:\n%s",
			errorLine, errorColumn, qPrintable(errorStr));
	return false;
  }
  QDomElement root = domDocument.documentElement();
  if( root.tagName() != "RDF" ) {
	qFatal("Root node is not RDF, it is %s", qPrintable(root.tagName()));
	return false;
  }
  QDomElement repo = root.firstChildElement("Repository");
  //qDebug() << repo.attribute("resource");
  for( QDomElement desc = repo.firstChildElement("Description"); 
	   !desc.isNull(); desc = desc.nextSiblingElement()) {
	QString name = desc.firstChildElement("Name").text().toLower();
	QString version = desc.firstChildElement("Version").text();
	QString release = desc.firstChildElement("Release").text();
	//qDebug() << desc.attribute("about");
	RPMNode rpmnode;
	if( nodes.contains(name)) rpmnode = nodes[name];
	if( name.isEmpty() ) continue;
	rpmnode.name = name;
	rpmnode.about = desc.attribute("about");
	rpmnode.version = version;
	rpmnode.release = release;
	for( QDomElement req = desc.firstChildElement("BuildPreReq"); 
		 !req.isNull(); req = req.nextSiblingElement("BuildPreReq")) {
	  if( req.hasAttribute("cond") ) continue;
	  QDomNodeList lst = req.elementsByTagName("resource");
	  for( int i = 0; i < lst.count(); ++i ) {
		QString req = lst.item(i).toElement().text().toLower();		
		if( !req.isEmpty() && !req.contains("::") && req != rpmnode.name ) 
		  rpmnode.requires.insert( req );
	  }
	}
	for( QDomElement req = desc.firstChildElement("Provides"); 
		 !req.isNull(); req = req.nextSiblingElement("Provides")) {
	  QDomNodeList lst = req.elementsByTagName("resource");
	  for( int i = 0; i < lst.count(); ++i ) {
		QString prov = lst.item(i).toElement().text().toLower();		
		if( !prov.isEmpty() ) 
		  rpmnode.provides.insert( prov );
	  }
	}
	rpmnode.provides.insert( rpmnode.name );
	nodes[rpmnode.name] = rpmnode;
  }
  return true;
}

QStringList RPMSorter::sort() const
{
  QMap<QString,RPMNode> nodes = this->nodes;
  for( QMap<QString,RPMNode>::iterator it = nodes.begin();
	   it != nodes.end(); ++it ) {
	if( (*it).requires.isEmpty() ) {
	  nodes[it.key()].requires.insert("START");
	}
  }
  RPMNode startnode;
  startnode.name="START";
  nodes["START"] = startnode;

  QStringList result;
  
  while( !nodes.isEmpty() ) {
	RPMNode current;
	for( QMap<QString,RPMNode>::iterator it = nodes.begin();
		 it != nodes.end(); ++it ) {
	  //qDebug() << (*it).name << " has " << (*it).requires.count() << " deps";
	  if( (*it).requires.isEmpty() ) {
		current = *it;
		nodes.erase(it);
		break;
	  }
	}
	if( current.name.isNull() ) {
	  std::cout << "Cycle detected. Remaining packages are" << std::endl;
	  dumpNodes(nodes);
	  qFatal("Bailing out!");
	}
	//qDebug() << qPrintable(current.name);
	result << current.name;
	for( QMap<QString,RPMNode>::iterator it = nodes.begin();
		 it != nodes.end(); ++it ) {
	  nodes[it.key()].requires.remove(current.name);
	  for( QSet<QString>::const_iterator it2 = current.provides.constBegin();
		   it2 != current.provides.constEnd(); ++it2 ) {
		nodes[it.key()].requires.remove(*it2);		
	  }
	}
  }
  return result;
}

void RPMSorter::dumpNodes() const
{
  dumpNodes(nodes);
}

void RPMSorter::dumpNodes( const QMap<QString,RPMNode>& nodes ) const
{
  for( QMap<QString,RPMNode>::const_iterator it = nodes.constBegin();
	   it != nodes.constEnd(); ++it ) {
	(*it).dumpNode();
  }
}

int main( int argc, char** argv ) {
    QCoreApplication app( argc, argv );

	if( argc < 2 ) {
	  std::cout << "Usage: " << argv[0] << " file1.rdf [file2.rdf ...]" << std::endl;
	  exit(1);
	}
	
	RPMSorter sorter;

	for( int i = 1; i < argc; ++i ) {
	  QFile file( argv[i] );
	  if (!file.open(QFile::ReadOnly | QFile::Text)) {
		qFatal( qPrintable(file.errorString()));
	  }
	  sorter.addFrom(&file);
	}
	//sorter.dumpNodes();
	std::cout << qPrintable( sorter.sort().join("\n") ) << std::endl;
	return 0;
}

--- NEW FILE: rpmsort.pro ---
######################################################################
# Automatically generated by qmake (2.00a) Tue Jul 19 17:25:11 2005
######################################################################

QT += xml
CONFIG += warn_on debug 

TEMPLATE = app
DEPENDPATH += .
INCLUDEPATH += .

# Input
SOURCES += main.cpp





More information about the commits mailing list