prt-get/src/package.cpp

343 lines
9.8 KiB
C++

////////////////////////////////////////////////////////////////////////
// FILE: package.cpp
// AUTHOR: Johannes Winkelmann, jw@tks6.net
// COPYRIGHT: (c) 2002 by Johannes Winkelmann
// ---------------------------------------------------------------------
// 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.
////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <cstdio>
#include <sys/stat.h>
#include <sys/utsname.h>
using namespace std;
#include "package.h"
#include "stringhelper.h"
using namespace StringHelper;
/*!
Create a package, which is not yet fully initialized, This is interesting
in combination with the lazy initialization
*/
Package::Package( const string& name,
const string& path )
: m_loaded( false )
{
m_data = new PackageData( name, path );
}
/*!
Create a fully initialized package. Most interesting when created from a
cache file
*/
Package::Package( const string& name,
const string& path,
const string& version,
const string& release,
const string& description,
const string& dependencies,
const string& url,
const string& optionals,
const string& maintainer,
const string& hasReadme,
const string& hasPreInstall,
const string& hasPostInstall)
: m_loaded( true )
{
m_data = new PackageData( name, path, version, release,
description, dependencies, url,
optionals, maintainer, hasReadme,
hasPreInstall, hasPostInstall );
}
Package::~Package()
{
delete m_data;
}
/*! \return the name of this package */
const string& Package::name() const
{
return m_data->name;
}
/*! \return the path to this package */
const string& Package::path() const
{
return m_data->path;
}
/*! \return the version of this package */
const string& Package::version() const
{
load();
return m_data->version;
}
/*! \return the release number of this package */
const string& Package::release() const
{
load();
return m_data->release;
}
/*! \return the description field of this package */
const string& Package::description() const
{
load();
return m_data->description;
}
/*! \return the dependency line of this package */
const string& Package::dependencies() const
{
load();
return m_data->depends;
}
/*! \return the url of this package */
const string& Package::url() const
{
load();
return m_data->url;
}
/*! \return the optional dependencies of this package */
const string& Package::optionals() const
{
load();
return m_data->optionals;
}
/*! \return the maintainer of this package */
const string& Package::maintainer() const
{
load();
return m_data->maintainer;
}
/*! \return whether or not this package has a readme file */
bool Package::hasReadme() const
{
load();
return m_data->hasReadme;
}
/*! \return a typically formatted version-release string */
string Package::versionReleaseString() const
{
load();
return m_data->versionReleaseString;
}
bool Package::hasPreInstall() const
{
return m_data->hasPreInstall;
}
bool Package::hasPostInstall() const
{
return m_data->hasPostInstall;
}
/*!
load from Pkgfile
*/
void Package::load() const
{
if ( m_loaded ) {
return;
}
m_loaded = true;
string fileName = m_data->path + "/" + m_data->name + "/Pkgfile";
// c IO is about four times faster then fstream :-(
FILE* fp = fopen( fileName.c_str(), "r" );
if ( fp == NULL ) {
return;
}
const int length = BUFSIZ;
char input[length];
string line;
time_t timeNow;
time(&timeNow);
struct utsname unameBuf;
if (uname(&unameBuf) != 0) {
unameBuf.release[0] = '\0';
}
while ( fgets( input, length, fp ) ) {
line = stripWhiteSpace( input );
if ( line.substr( 0, 8 ) == "version=" ) {
m_data->version = getValueBefore( getValue( line, '=' ), '#' );
m_data->version = stripWhiteSpace( m_data->version );
expandShellCommands(m_data->version, timeNow, unameBuf);
} else if ( line.substr( 0, 8 ) == "release=" ) {
m_data->release = getValueBefore( getValue( line, '=' ), '#' );
m_data->release = stripWhiteSpace( m_data->release );
} else if ( line[0] == '#' ) {
while ( !line.empty() &&
( line[0] == '#' || line[0] == ' ' || line[0] == '\t' ) ) {
line = line.substr( 1 );
}
string::size_type pos = line.find( ':' );
if ( pos != string::npos ) {
if ( startsWithNoCase( line, "desc" ) ) {
m_data->description =
stripWhiteSpace( getValue( line, ':' ) );
} else if ( startsWithNoCase( line, "maint" ) ) {
m_data->maintainer =
stripWhiteSpace( getValue( line, ':' ) );
} else if ( startsWithNoCase( line, "url" ) ) {
m_data->url = stripWhiteSpace( getValue( line, ':' ) );
} else if ( startsWithNoCase( line, "optional" ) or
startsWithNoCase( line, "nice to have" ) ) {
string softdeps = stripWhiteSpace( getValue( line, ':' ) );
StringHelper::replaceAll( softdeps, " ", "," );
StringHelper::replaceAll( softdeps, ",,", "," );
StringHelper::replaceAll( softdeps, "(", "" );
StringHelper::replaceAll( softdeps, ")", "" );
m_data->optionals = softdeps;
} else if ( startsWithNoCase( line, "dep" ) ) {
string depends = stripWhiteSpace( getValue( line, ':' ) );
StringHelper::replaceAll( depends, " ", "," );
StringHelper::replaceAll( depends, ",,", "," );
m_data->depends = depends;
}
}
}
}
fclose( fp );
m_data->generateVersionReleaseString();
string file = m_data->path + "/" + m_data->name + "/README";
struct stat buf;
if ( stat( file.c_str(), &buf ) != -1) {
m_data->hasReadme = true;
}
file = m_data->path + "/" + m_data->name + "/pre-install";
if ( stat( file.c_str(), &buf ) != -1) {
m_data->hasPreInstall = true;
}
file = m_data->path + "/" + m_data->name + "/post-install";
if ( stat( file.c_str(), &buf ) != -1) {
m_data->hasPostInstall = true;
}
}
void Package::setDependencies( const std::string& dependencies )
{
m_data->depends = dependencies;
}
void Package::setOptionals( const std::string& optionals )
{
m_data->optionals = optionals;
}
PackageData::PackageData( const string& name_,
const string& path_,
const string& version_,
const string& release_,
const string& description_,
const string& dependencies_,
const string& url_,
const string& optionals_,
const string& maintainer_,
const string& hasReadme_,
const string& hasPreInstall_,
const string& hasPostInstall_ )
: name( name_ ),
path( path_ ),
version( version_ ),
release( release_ ),
description( description_ ),
depends( dependencies_ ),
url( url_ ),
optionals( optionals_ ),
maintainer( maintainer_ )
{
generateVersionReleaseString();
hasReadme = ( stripWhiteSpace( hasReadme_ ) == "yes" );
hasPreInstall = ( stripWhiteSpace( hasPreInstall_ ) == "yes" );
hasPostInstall = ( stripWhiteSpace( hasPostInstall_ ) == "yes" );
}
void PackageData::generateVersionReleaseString()
{
versionReleaseString = version + "-" + release;
}
void Package::expandShellCommands(std::string& input,
const time_t& timeNow,
const struct utsname unameBuf)
{
// TODO: consider dropping either of the tagsets, depending on feedback
static const int TAG_COUNT = 2;
string startTag[TAG_COUNT] = { "`", "$(" };
string endTag[TAG_COUNT] = { "`", ")" };
for (int i = 0; i < TAG_COUNT; ++i) {
string::size_type pos, dpos = 0;
pos = 0;
while ((pos = input.find(startTag[i], pos)) != string::npos) {
input = replaceAll(input,
startTag[i] + "uname -r" + endTag[i],
unameBuf.release);
dpos = input.find(startTag[i] + "date");
if (dpos != string::npos) {
// NOTE: currently only works for one date pattern
string::size_type startpos, endpos;
endpos = input.find(endTag[i], dpos+1);
startpos = input.find('+', dpos+1);
string format = input.substr(startpos+1, endpos-startpos-1);
// support date '+...' and date "+..."
int len = format.length();
if (format[len-1] == '\'' || format[len-1] == '"') {
format = format.substr(0, len-1);
}
char timeBuf[32];
strftime(timeBuf, 32, format.c_str(), localtime(&timeNow));
input = input.substr(0, dpos) + timeBuf +
input.substr(endpos+1);
}
++pos;
}
}
}