diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 37333bf25ad9a4c538250f5af2f9f1d666362883 (patch) | |
tree | c45e8df5b9efbffe07eb3d9340df7811c7e16943 /kpackage/fbsdInterface.cpp | |
download | tdeadmin-37333bf25ad9a4c538250f5af2f9f1d666362883.tar.gz tdeadmin-37333bf25ad9a4c538250f5af2f9f1d666362883.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeadmin@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kpackage/fbsdInterface.cpp')
-rw-r--r-- | kpackage/fbsdInterface.cpp | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/kpackage/fbsdInterface.cpp b/kpackage/fbsdInterface.cpp new file mode 100644 index 0000000..980ad36 --- /dev/null +++ b/kpackage/fbsdInterface.cpp @@ -0,0 +1,641 @@ +/* +** Copyright (C) 2000 by Alex Hayward <xelah@xelah.com> +*/ + + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + + + +#include <errno.h> +#include <stdlib.h> +#include <assert.h> +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/utsname.h> + +#include <qstringlist.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include "fbsdInterface.h" +#include "kpackage.h" +#include "updateLoc.h" +#include "cache.h" +#include "options.h" + +#define PKG_INFO_BIN "/usr/sbin/pkg_info" +#define PKG_ADD_BIN "/usr/sbin/pkg_add" +#define PKG_DELETE_BIN "/usr/sbin/pkg_delete" + +#define INFO_SEPARATOR "f;g#z-@IqbX%" + +fbsdInterface::fbsdInterface():pkgInterface() { + head = "BSD"; + name = i18n("BSD"); + icon = "bsd"; + + pict = UserIcon(icon); + updated_pict = UserIcon("bupdated"); + new_pict = UserIcon("bnew"); + + packagePattern = "*.tgz *.tbz"; + typeID = "/tbz"; + + QDict <bsdPortsIndexItem> ports(17777, false); + queryMsg = i18n("Querying package list: "); + + locatedialog = new Locations(i18n("Location of BSD Packages and Ports")); + locatedialog->dLocations(1, 1, this, i18n("Ports"), "Pkg", "*.tbz", + i18n("Location of Ports Tree (e.g. /usr/ports or /usr/opt)"),FALSE); + locatedialog->dLocations(1, 6, this, i18n("Packages"), "Pkg", "*.tbz", + i18n("Location of Folders Containing BSD Packages or Package Trees")); + connect(locatedialog, SIGNAL(returnVal(LcacheObj *)), this, SLOT(setAvail(LcacheObj *))); + locatedialog->apply_slot(); + + paramsInst.append(new param(i18n("Ignore Scripts"),FALSE,FALSE,"-I")); + paramsInst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"-f")); + paramsInst.append(new param(i18n("Test (do not install)"),FALSE,FALSE,"-n")); + + paramsUninst.append(new param(i18n("Ignore Scripts"),FALSE,FALSE, "-I")); + paramsUninst.append(new param(i18n("Check Dependencies"),TRUE,TRUE, "-f")); + paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE, "-n")); + + hasProgram = ifExe("pkg_info") && ifExe("pkg_add"); +} + +fbsdInterface::~fbsdInterface() { + +} + +bool fbsdInterface::isType(char *, const QString &fname) { + // These files are .tgz or .tbz files. Pass it to pkg_info and see whether it + // succeeds. + if (hasProgram) { + QString cmd = PKG_INFO_BIN; // cmd += "_q"; + cmd += " -q "; + cmd += fname; + kpty->run(cmd); + + if (!kpty->Result) + return true; + else + return false; + } else { + return false; + } +} + +static void insertGroups(QMap<QString, QString> *a, QString cats) +{ + /* Create the list of groups (which is space-separated), and then + ** iterate through it with the iterator i. count is just to + ** distinguish the first entry (count==0) from the rest, since + ** the key used in a->insert() needs to be different. + */ + QStringList grlist = QStringList::split(' ',cats); + unsigned int count = 0; + for (QStringList::Iterator i = grlist.begin(); + i != grlist.end(); ++count,++i) { + a->insert( (count ? "also in" : "group"), *i); + } +} + +packageInfo *fbsdInterface::getPackageInfo(char mode, const QString &pname, const QString &version) { + QString name( pname); + bool installed = false; + kpackage->setStatus(i18n("Getting package info")); + + kdDebug() << "Looking at package " << pname << endl; + + if (mode == 'i' && !version.isEmpty()) { + name += "-" + version; + } + + QMap<QString, QString> a; + + // Get the package name first (for mode = 'u'). + if (mode == 'u') { + QString cmd = PKG_INFO_BIN; // cmd += "_qf"; + cmd += " -qf "; + cmd += name; + QStringList list = kpty->run(cmd); + + int last_dir = name.find('/'); + if (last_dir != -1) { + a["filename"] = name.mid(last_dir+1); + a["base"] = name.left(last_dir + 1); + } else { + a["filename"] = name; + a["base"] = ""; + } + + if (list.count() > 0) { + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + // Look for a line of the form '@name <pkgname>' + if ((*it).left(5) == "@name") { + QString n = (*it).mid(6); + addNV(a, n); + break; + } + } + } else addNV(a, name); + } + + // Open a pipe to a pkg_info process in order to read the one line comment + // and description for the package. This works for both installed packages + // and for files. + QString cmd = PKG_INFO_BIN; // cmd += "_q"; + cmd += " -q "; + cmd += name; + QStringList list = kpty->run(cmd); + + QStringList::Iterator it = list.begin(); + + + if (list.count() > 0) { + QStringList::Iterator it = list.begin(); + a["summary"] = *it; + it++; + QString desc; + int prevlen = 0, len; + for ( ; it != list.end(); ++it ) { + len = (*it).length(); + desc += (*it); + // kdDebug() << len << " " << prevlen << "=" << *it << "\n"; + if (len > 0 || prevlen > 0) + desc += "<br>\n"; + prevlen = (*it).length(); + } + // kdDebug( << desc << "\n"; + bsdPortsIndexItem *inditem = ports[name]; + + if (inditem) { + installed = inditem->installed; + a["maintainer"] = inditem->fields[bsdPortsIndexItem::MAINT]; + + insertGroups(&a,inditem->fields[bsdPortsIndexItem::CATS]); + + a["build depends"] = !inditem->fields[bsdPortsIndexItem::BDEPS].isEmpty() ? inditem->fields[bsdPortsIndexItem::BDEPS] : i18n("none"); + a["available as"] = inditem->bin ? (inditem->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port"); + } + a["description"] = desc; + } else { + kpackage->setStatus(QString::null); + return 0; + } + + packageInfo *ret = new packageInfo(a, this); + ret->packageState = installed? packageInfo::INSTALLED : packageInfo::AVAILABLE; + ret->fixup(); + if (!installed) ret->smerge(typeID); + kpackage->setStatus(QString::null); + return ret; +} + +QStringList fbsdInterface::getChangeLog(packageInfo *) { + return 0; +} + + +bool fbsdInterface::filesTab(packageInfo *) { + return TRUE; +} + +bool fbsdInterface::changeTab(packageInfo *) { + return FALSE; +} + +QStringList fbsdInterface::getFileList(packageInfo *p) { + + // Run pkg_info on the package name to get the file list. + // The file list is returned on stdout, one per line. + kpackage->setStatus(i18n("Getting file list")); + + QStringList ret; + + // Find the full name 'name-version', or just 'name' if version is empty. + // Check first that it is actually installed. + QString name( p->getProperty("filename")); + + if (!name.isEmpty() && (p->packageState != packageInfo::INSTALLED)) { + QString qbname( p->getProperty("base")); + if (!qbname.isEmpty()) + name = qbname + "/" + name; + } else { + if (!p->hasProperty("name")) { + ret.append(i18n("Can't find package name!")); + kpackage->setStatus(QString::null); + return ret; + } + + name = p->getProperty("name"); + + QString version( p->getProperty("version")); + if (!version.isEmpty()) { + name = name + "-" + version; + } + } + + // Open a pipe to a pkg_info process in order to read the file list. + // This works for both installed packages and for files. + QString cmd = PKG_INFO_BIN; // cmd += "_Lq"; + cmd += " -L -q "; + cmd += name; + QStringList list = kpty->run(cmd); + + ret = list; + + kpackage->setStatus(QString::null); + return ret; +} + + +// QPtrList<char> *verify(packageInfo *p, QPtrList<char> *files); + +QString fbsdInterface::doUninstall(int uninstallFlags, const QString &packs, bool &) +{ + + QString s = PKG_DELETE_BIN; + s += " "; + s += setOptions(uninstallFlags, paramsUninst); + s += packs; + + kdDebug() << "uCMD=" << s << "\n"; + + return s; +} + + +QString fbsdInterface::doInstall(int installFlags, const QString &packs, bool &) +{ + + QString s = PKG_ADD_BIN; + s += " "; + s += setOptions(installFlags, paramsInst); + s += packs; + + kdDebug() << "iCMD=" << s << "\n"; + + return s; +} + +QString fbsdInterface::uninstall(int uninstallFlags, packageInfo *p, bool &test) +{ + QString packs( p->getProperty("name")); + QString vers( p->getProperty("version")); + if (vers.length() > 0) packs += "-" + vers; + + return doUninstall(uninstallFlags, packs, test); +} + +QString fbsdInterface::uninstall(int uninstallFlags, QPtrList<packageInfo> *p, bool &test) +{ + QString packs ; + packageInfo *i; + + for (i = p->first(); i!= 0; i = p->next()) { + packs += i->getProperty("name"); + QString vers( i->getProperty("version")); + if (vers.length() != 0) packs += "-" + vers; + packs += " "; + } + return doUninstall( uninstallFlags, packs, test); +} + +QStringList fbsdInterface::FindFile(const QString &, bool) { + QStringList tmp; + return tmp; +} + +bool fbsdInterface::parseName(const QString &name, QString *n, QString *v) { + int m1; + + m1 = name.findRev('-'); + if (m1 <= 0) return false; + *n = name.left(m1); + *v = name.right(name.length() - m1 - 1); + return true; +} + +void fbsdInterface::addNV(QMap<QString, QString> &d, const QString &name) { + QString n, v; + + if (!parseName(name, &n, &v)) { + n = name; + v = QString::null; + } + + d.insert("name", n); + d.insert("version", v); +} + + //public slots +void fbsdInterface::setLocation() { + locatedialog->restore(); +} + +void fbsdInterface::setAvail(LcacheObj *slist) { + kdDebug() << k_funcinfo << endl; + + if (packageLoc) delete packageLoc; + packageLoc = slist; + + cacheObj *cp = packageLoc->first(); + + if (cp && !cp->location.isEmpty()) { + for (; cp != 0; cp = packageLoc->next()) { + QString oldloc = cp->location; + cp->location += "/INDEX"; + QString s = getPackList(cp); + if (!s.isEmpty()) bsdPortsIndexItem::processFile(this, QFile::encodeName(s), true, oldloc); + cp->location = oldloc; + } + } + + // Try /usr/port/INDEX-<major version> on FreeBSD + struct utsname fbsdName; + if(uname(&fbsdName) != -1 && !strcmp(fbsdName.sysname, "FreeBSD")) + bsdPortsIndexItem::processFile(this, QString("/usr/ports/INDEX-").append(*fbsdName.release), false, "/usr/ports"); + + // Try the standard ports tree locations. + bsdPortsIndexItem::processFile(this, "/usr/ports/INDEX", false, "/usr/ports"); // FreeBSD/OpenBSD + bsdPortsIndexItem::processFile(this, "/usr/opt/INDEX", false, "/usr/opt"); // NetBSD +} + + +void fbsdInterface::listPackages(QPtrList<packageInfo> *pki) { + kdDebug() << k_funcinfo << endl; + + listInstalledPackages(pki); + + + QDictIterator<bsdPortsIndexItem> it( ports ); // See QDictIterator + for( ; it.current(); ++it ) { + bsdPortsIndexItem *scan = it.current(); + if (!scan->installed /*&& scan->bin */) { + QMap<QString, QString> a; + + addNV(a, scan->fields[bsdPortsIndexItem::NAME]); + a["summary"] = scan->fields[bsdPortsIndexItem::COMMENT]; + a["maintainer"] = scan->fields[bsdPortsIndexItem::MAINT]; + + insertGroups(&a,scan->fields[bsdPortsIndexItem::CATS]); + + a["run depends"] = !scan->fields[bsdPortsIndexItem::RDEPS].isEmpty() ? scan->fields[bsdPortsIndexItem::RDEPS] : i18n("none"); + a["build depends"] = !scan->fields[bsdPortsIndexItem::BDEPS].isEmpty() ? scan->fields[bsdPortsIndexItem::BDEPS] : i18n("none"); + a["available as"] = scan->bin ? (scan->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port"); + + a["filename"] = scan->bin_filename; + a["base"] = scan->bin_filename_base; + + packageInfo *info = new packageInfo(a, this); + info->packageState = packageInfo::AVAILABLE; + info->smerge(typeID); + info->fixup(); + info->pkgInsert(pki, typeID, false); +// pki->append(info); + } + } + +} + +int fbsdInterface::parseItem(QStringList::Iterator &it, QString &name, QString &value, QString separator, QStringList list ) { + if ((*it).left(separator.length()) == separator) { + name = *it; + name = name.mid(separator.length()); + } else { + return -1; + } + if (it == list.end()) + return -1; + it++; + + value = ""; + int prevlen = 0, len; + while ((*it).left(separator.length()) != separator) { + len = (*it).length(); + value += *it; + if (len > 0 || prevlen > 0) + value += "<br>"; + if (it == list.end()) + return -1; + prevlen = (*it).length(); + it++; + } + return 1; +} + +int fbsdInterface::pathInfo(QMap<QString, QString> &a) +{ + int pkg_state = packageInfo::INSTALLED; + if (a["group"].isEmpty()) { + QString s, ps; + ps = a["name"]; + if (ps.isEmpty()) + s = ps; + else + s = "<anonymous>"; + + ps = a["version"]; + if (!ps.isEmpty()) + s.append(QString("-")+(ps)); + + kdDebug() << "Package " << (s) << " has no group." << endl; + + /* This must be an installed package with no INDEX entry, + ** which usually means that the port has been updated. + */ + QString cmd = PKG_INFO_BIN; + // cmd += "2"; + cmd += " -ol "; + cmd += INFO_SEPARATOR; + QStringList list = kpty->run(cmd); + + if (list.count() > 0) { + QStringList::Iterator it = list.begin(); + QString name, value; + parseItem(it, name, value, INFO_SEPARATOR, list); // Information + parseItem(it, name, value, INFO_SEPARATOR, list); // Path + + int pos = value.findRev('/'); + value.truncate(pos); + a["group"] = value; + } else { + kdDebug() << "Could not read package origin info." << endl; + } + } + return pkg_state; +} + + void fbsdInterface::listInstalledPackages(QPtrList<packageInfo> *pki) { + kdDebug() << k_funcinfo << endl; + + // Open a pipe to a pkg_info process in order to read the comment, name + // and description for the packages. + + kpackage->setStatus(i18n("Querying BSD packages database for installed packages")); + + QString cmd = PKG_INFO_BIN; + cmd += " -acdl "; + cmd += INFO_SEPARATOR; + QStringList list = kpty->run(cmd); + + // We should now get: + // INFO_SEPARATORInformation for pkgname: + // + // INFO_SEPARATORComment: + // <one line description> + // + // INFO_SEPARATORDescription: + // <description> + // + // + // INFO_SEPARATOR + // INFO_SEPARATORInformation for [etc] + + QMap<QString, QString> a; + QString name, value; + if (list.count() > 0) { + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + + parseItem(it, name, value, INFO_SEPARATOR, list); // Information + // Find the last word on this line (which should be the package name) minus a trailing :. + QString pkg = name.section(' ',-1); + if (pkg.isEmpty()) { + KpMsgE(i18n("Unexpected output from pkg_info (looking for package name): %1").arg(value), TRUE); + kpackage->setStatus(QString::null); + return; + } else { + if (pkg[pkg.length()-1] == ':') { + pkg.truncate(pkg.length()-1); + } + } + addNV(a, pkg); + + parseItem(it, name, value, INFO_SEPARATOR, list); //Comment + a["summary"] = value; + + + parseItem(it, name, value, INFO_SEPARATOR, list); //Description + + bsdPortsIndexItem *inditem = ports[pkg]; + + if (inditem) { + inditem->installed = true; + + a["maintainer"] = inditem->fields[bsdPortsIndexItem::MAINT]; + + insertGroups(&a,inditem->fields[bsdPortsIndexItem::CATS]); + if (a["group"].isEmpty()) { + kdDebug() << "Line <" << name << "=" << value << "> has no group?" << endl; + } + + a["run depends"] = !inditem->fields[bsdPortsIndexItem::RDEPS].isEmpty() ? + inditem->fields[bsdPortsIndexItem::RDEPS] : i18n("none"); + a["build depends"] = !inditem->fields[bsdPortsIndexItem::BDEPS].isEmpty() ? + inditem->fields[bsdPortsIndexItem::BDEPS] : i18n("none"); + a["available as"] = inditem->bin ? (inditem->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port"); + } + + a["description"] = value; + + int pkg_state = pathInfo(a); + packageInfo *info = new packageInfo(a, this); + info->packageState = pkg_state; + + info->fixup(); + //pki->append(info); + info->pkgInsert(pki, typeID, true); + + } + } +} + + +bsdPortsIndexItem::bsdPortsIndexItem(fbsdInterface *parent, char *desc, bool binaries, const QString &dname) : bin(binaries), port(!binaries), installed(false) { + fields = QStringList::split('|', desc, TRUE); + QString name = fields[NAME]; + + bsdPortsIndexItem *port = parent->ports[name]; + if (port) { + port->bin = port->bin || bin; + port->port = port->port || port; + if (binaries) { + port->bin_filename = QString(name) + ".tbz"; + port->bin_filename_base = dname + "/"; + } + fields[NAME] = ""; // Acts as a 'not used' tag. + return; + + } + if (binaries) { + bin_filename = QString(name) + ".tbz"; + bin_filename_base = dname + "/"; + } + +} + +void bsdPortsIndexItem::processFile(fbsdInterface *parent, const QString &fname, bool binaries, const QString &dname) { + // Read the file in to a buffer and null terminate it. + + struct stat s; + + if (stat(fname.ascii(), &s) == -1) { + // Error message? + return; + } + + char *index = (char *) malloc(s.st_size); + int fd; + + fd = open(fname.ascii(), O_RDONLY); + if (fd == -1) { + // Error message? + return; + } + + int size = read(fd, index, s.st_size); + index[size] = 0; + close(fd); + + + // Go through each line and create a new bsdPortsIndexItem. + char *line = strtok(index, "\n"); + while (line != 0) { + bsdPortsIndexItem *i = new bsdPortsIndexItem(parent, line, binaries, dname + "/All"); + if (i->fields[NAME].isEmpty()) { + delete i; + } else { + parent->ports.insert(i->fields[NAME] , i); + } + line = strtok(0, "\n"); + } +} + + +#include "fbsdInterface.moc" |