2005-11-09 16:43:05 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// FILE: installtransaction.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 <unistd.h>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <iostream>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <list>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2006-04-07 03:49:13 -04:00
|
|
|
#include <time.h>
|
2005-11-09 16:43:05 -05:00
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
|
|
#include "installtransaction.h"
|
|
|
|
#include "repository.h"
|
|
|
|
#include "pkgdb.h"
|
|
|
|
#include "stringhelper.h"
|
|
|
|
#include "argparser.h"
|
|
|
|
#include "process.h"
|
|
|
|
#include "configuration.h"
|
|
|
|
|
|
|
|
#ifdef USE_LOCKING
|
|
|
|
#include "lockfile.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace StringHelper;
|
|
|
|
|
|
|
|
|
|
|
|
const string InstallTransaction::PKGMK_DEFAULT_COMMAND = "/usr/bin/pkgmk";
|
|
|
|
const string InstallTransaction::PKGADD_DEFAULT_COMMAND = "/usr/bin/pkgadd";
|
|
|
|
const string InstallTransaction::PKGRM_DEFAULT_COMMAND = "/usr/bin/pkgrm";
|
|
|
|
|
2006-10-19 04:34:44 -04:00
|
|
|
/*!
|
|
|
|
Create a nice InstallTransaction
|
|
|
|
\param names a list of port names to be installed
|
|
|
|
\param repo the repository to look for packages
|
|
|
|
\param pkgDB the pkgDB with already installed packages
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallTransaction( const list<string>& names,
|
|
|
|
const Repository* repo,
|
|
|
|
PkgDB* pkgDB,
|
|
|
|
const Configuration* config )
|
2019-03-01 15:33:11 -05:00
|
|
|
: m_pkgDB( pkgDB ),
|
|
|
|
m_resolver(),
|
|
|
|
m_repo( repo ),
|
2006-10-19 04:34:44 -04:00
|
|
|
m_depCalced( false ),
|
2019-03-01 15:33:11 -05:00
|
|
|
m_installedPackages(),
|
|
|
|
m_alreadyInstalledPackages(),
|
|
|
|
m_ignoredPackages(),
|
|
|
|
m_depNameList(),
|
|
|
|
m_depList(),
|
|
|
|
m_missingPackages(),
|
|
|
|
m_installErrors(),
|
2006-10-19 04:34:44 -04:00
|
|
|
m_config( config )
|
|
|
|
{
|
|
|
|
list<string>::const_iterator it = names.begin();
|
|
|
|
for ( ; it != names.end(); ++it ) {
|
|
|
|
m_packages.push_back( make_pair( *it, m_repo->getPackage( *it ) ) );
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2006-10-19 04:34:44 -04:00
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
/*!
|
|
|
|
Create a nice InstallTransaction
|
|
|
|
\param names a list of port names to be installed
|
|
|
|
\param repo the repository to look for packages
|
|
|
|
\param pkgDB the pkgDB with already installed packages
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallTransaction( const list<char*>& names,
|
|
|
|
const Repository* repo,
|
|
|
|
PkgDB* pkgDB,
|
|
|
|
const Configuration* config )
|
2019-03-01 15:33:11 -05:00
|
|
|
: m_pkgDB( pkgDB ),
|
|
|
|
m_resolver(),
|
|
|
|
m_repo( repo ),
|
2005-11-09 16:43:05 -05:00
|
|
|
m_depCalced( false ),
|
2019-03-01 15:33:11 -05:00
|
|
|
m_installedPackages(),
|
|
|
|
m_alreadyInstalledPackages(),
|
|
|
|
m_ignoredPackages(),
|
|
|
|
m_depNameList(),
|
|
|
|
m_depList(),
|
|
|
|
m_missingPackages(),
|
|
|
|
m_installErrors(),
|
2005-11-09 16:43:05 -05:00
|
|
|
m_config( config )
|
|
|
|
{
|
|
|
|
list<char*>::const_iterator it = names.begin();
|
|
|
|
for ( ; it != names.end(); ++it ) {
|
|
|
|
m_packages.push_back( make_pair( *it, m_repo->getPackage( *it ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-10-19 04:34:44 -04:00
|
|
|
|
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
/*!
|
|
|
|
Create a nice InstallTransaction
|
|
|
|
\param names a list of port names to be installed
|
|
|
|
\param repo the repository to look for packages
|
|
|
|
\param pkgDB the pkgDB with already installed packages
|
|
|
|
*/
|
2006-10-19 04:34:44 -04:00
|
|
|
InstallTransaction::InstallTransaction( const string& name,
|
2005-11-09 16:43:05 -05:00
|
|
|
const Repository* repo,
|
|
|
|
PkgDB* pkgDB,
|
|
|
|
const Configuration* config )
|
2019-03-01 15:33:11 -05:00
|
|
|
: m_pkgDB( pkgDB ),
|
|
|
|
m_resolver(),
|
|
|
|
m_repo( repo ),
|
2005-11-09 16:43:05 -05:00
|
|
|
m_depCalced( false ),
|
2019-03-01 15:33:11 -05:00
|
|
|
m_installedPackages(),
|
|
|
|
m_alreadyInstalledPackages(),
|
|
|
|
m_ignoredPackages(),
|
|
|
|
m_depNameList(),
|
|
|
|
m_depList(),
|
|
|
|
m_missingPackages(),
|
|
|
|
m_installErrors(),
|
2005-11-09 16:43:05 -05:00
|
|
|
m_config( config )
|
|
|
|
{
|
2006-10-19 04:34:44 -04:00
|
|
|
m_packages.push_back( make_pair( name, m_repo->getPackage( name ) ) );
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\return packages where building/installation failed
|
|
|
|
*/
|
|
|
|
const list< pair<string, InstallTransaction::InstallInfo> >&
|
|
|
|
InstallTransaction::installError() const
|
|
|
|
{
|
|
|
|
return m_installErrors;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
install (commit) a transaction
|
|
|
|
\param parser the argument parser
|
|
|
|
\param update whether this is an update operation
|
|
|
|
\return returns an InstallResult telling whether installation worked
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallResult
|
|
|
|
InstallTransaction::install( const ArgParser* parser,
|
2023-03-12 07:37:16 -04:00
|
|
|
bool update )
|
2005-11-09 16:43:05 -05:00
|
|
|
{
|
|
|
|
if ( m_packages.empty() ) {
|
|
|
|
return NO_PACKAGE_GIVEN;
|
|
|
|
}
|
2006-04-04 12:22:35 -04:00
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
list<string> ignoredPackages;
|
|
|
|
StringHelper::split(parser->ignore(), ',', ignoredPackages);
|
|
|
|
|
|
|
|
list< pair<string, const Package*> >::iterator it = m_packages.begin();
|
|
|
|
for ( ; it != m_packages.end(); ++it ) {
|
|
|
|
const Package* package = it->second;
|
2006-04-04 12:22:35 -04:00
|
|
|
|
|
|
|
if (find(ignoredPackages.begin(),
|
|
|
|
ignoredPackages.end(),
|
2005-11-09 16:43:05 -05:00
|
|
|
it->first) != ignoredPackages.end() ) {
|
|
|
|
m_ignoredPackages.push_back(it->first);
|
|
|
|
continue;
|
|
|
|
}
|
2006-04-04 12:22:35 -04:00
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( package == NULL ) {
|
|
|
|
m_missingPackages.push_back( make_pair( it->first, string("") ) );
|
2023-03-12 07:37:16 -04:00
|
|
|
if ( parser->group() ) {
|
2005-11-09 16:43:05 -05:00
|
|
|
return PACKAGE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// consider aliases here, but don't show them specifically
|
|
|
|
if ( !update && m_pkgDB->isInstalled( package->name(), true ) ) {
|
|
|
|
// ignore
|
|
|
|
m_alreadyInstalledPackages.push_back( package->name() );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
InstallTransaction::InstallResult result;
|
|
|
|
InstallInfo info( package->hasReadme() );
|
|
|
|
if ( parser->isTest() ||
|
|
|
|
(result = installPackage( package, parser, update, info )) == SUCCESS) {
|
|
|
|
|
2023-05-31 08:59:55 -04:00
|
|
|
m_installedPackages.push_back( make_pair( package->path()
|
|
|
|
+ "/" + package->name(), info));
|
2005-11-09 16:43:05 -05:00
|
|
|
} else {
|
|
|
|
|
|
|
|
// log failures are critical
|
|
|
|
if ( result == LOG_DIR_FAILURE ||
|
|
|
|
result == LOG_FILE_FAILURE ||
|
|
|
|
result == NO_LOG_FILE ||
|
|
|
|
result == CANT_LOCK_LOG_FILE ||
|
|
|
|
|
|
|
|
// or pkgdest
|
|
|
|
result == PKGDEST_ERROR ) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_installErrors.push_back( make_pair(package->name(), info) );
|
2023-03-12 07:37:16 -04:00
|
|
|
if ( parser->group() ) {
|
2005-11-09 16:43:05 -05:00
|
|
|
return PKGMK_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Install a single package
|
|
|
|
\param package the package to be installed
|
|
|
|
\param parser the argument parser to be used
|
|
|
|
\param update whether this is an update transaction
|
|
|
|
\param info store pre and post install information
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallResult
|
|
|
|
InstallTransaction::installPackage( const Package* package,
|
|
|
|
const ArgParser* parser,
|
|
|
|
bool update,
|
|
|
|
InstallTransaction::InstallInfo& info )
|
|
|
|
const
|
|
|
|
{
|
|
|
|
|
|
|
|
InstallTransaction::InstallResult result = SUCCESS;
|
|
|
|
#ifdef USE_LOCKING
|
|
|
|
LockFile lockFile;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int fdlog = -1;
|
2006-04-04 12:22:35 -04:00
|
|
|
string logFile = "";
|
2006-04-07 03:49:13 -04:00
|
|
|
string timestamp;
|
2006-04-14 04:34:17 -04:00
|
|
|
|
2006-04-07 03:49:13 -04:00
|
|
|
string commandName = "prt-get";
|
|
|
|
if ( parser->wasCalledAsPrtCached() ) {
|
|
|
|
commandName = "prt-cache";
|
|
|
|
}
|
|
|
|
|
2006-04-14 04:34:17 -04:00
|
|
|
// - initial information about the package to be build
|
|
|
|
string message;
|
|
|
|
message = commandName + ": ";
|
|
|
|
if (update) {
|
|
|
|
message += "updating ";
|
|
|
|
} else {
|
|
|
|
message += "installing ";
|
|
|
|
}
|
|
|
|
message += package->path() + "/" + package->name();
|
|
|
|
cout << message << endl;
|
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( m_config->writeLog() ) {
|
2006-04-04 12:22:35 -04:00
|
|
|
logFile = m_config->logFilePattern();
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( logFile == "" ) {
|
|
|
|
return NO_LOG_FILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringHelper::replaceAll( logFile, "%n", package->name() );
|
|
|
|
StringHelper::replaceAll( logFile, "%p", package->path() );
|
|
|
|
StringHelper::replaceAll( logFile, "%v", package->version() );
|
|
|
|
StringHelper::replaceAll( logFile, "%r", package->release() );
|
|
|
|
|
|
|
|
#ifdef USE_LOCKING
|
|
|
|
lockFile.setFile( logFile );
|
|
|
|
if ( !lockFile.lockWrite() ) {
|
|
|
|
cout << "here" << logFile << endl;
|
|
|
|
return CANT_LOCK_LOG_FILE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
size_t pos = logFile.find_last_of( "/" );
|
|
|
|
if ( pos != string::npos ) {
|
|
|
|
if ( !Repository::createOutputDir( logFile.substr( 0, pos ) ) ) {
|
|
|
|
return LOG_DIR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !m_config->appendLog() ) {
|
|
|
|
unlink( logFile.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
fdlog = open( logFile.c_str(),
|
|
|
|
O_APPEND | O_WRONLY | O_CREAT, 0666 );
|
|
|
|
|
|
|
|
if ( fdlog == -1 ) {
|
|
|
|
return LOG_FILE_FAILURE;
|
|
|
|
}
|
2006-09-10 14:22:31 -04:00
|
|
|
|
2006-04-14 04:34:17 -04:00
|
|
|
write( fdlog, message.c_str(), message.length());
|
|
|
|
write( fdlog, "\n", 1);
|
2006-04-07 03:49:13 -04:00
|
|
|
|
|
|
|
time_t startTime;
|
|
|
|
time(&startTime);
|
|
|
|
timestamp = ctime(&startTime);
|
|
|
|
timestamp = commandName + ": starting build " + timestamp;
|
|
|
|
write( fdlog, timestamp.c_str(), timestamp.length());
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
string pkgdir = package->path() + "/" + package->name();
|
|
|
|
chdir( pkgdir.c_str() );
|
|
|
|
|
|
|
|
string runscriptCommand = "sh";
|
|
|
|
if (m_config->runscriptCommand() != "") {
|
|
|
|
runscriptCommand = m_config->runscriptCommand();
|
|
|
|
}
|
2023-05-31 08:59:55 -04:00
|
|
|
if (parser->installRoot() != "") {
|
|
|
|
runscriptCommand = "chroot " + parser->installRoot() + runscriptCommand;
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
// -- pre-install
|
|
|
|
struct stat statData;
|
|
|
|
if ((parser->execPreInstall() || m_config->runScripts()) &&
|
|
|
|
stat((pkgdir + "/" + "pre-install").c_str(), &statData) == 0) {
|
|
|
|
Process preProc( runscriptCommand,
|
|
|
|
pkgdir + "/" + "pre-install",
|
|
|
|
fdlog );
|
|
|
|
if (preProc.executeShell()) {
|
|
|
|
info.preState = FAILED;
|
|
|
|
} else {
|
|
|
|
info.preState = EXEC_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- build
|
|
|
|
string cmd = PKGMK_DEFAULT_COMMAND;
|
|
|
|
if (m_config->makeCommand() != "") {
|
|
|
|
cmd = m_config->makeCommand();
|
|
|
|
}
|
|
|
|
|
|
|
|
string args = "-d " + parser->pkgmkArgs();
|
|
|
|
Process makeProc( cmd, args, fdlog );
|
|
|
|
if ( makeProc.executeShell() ) {
|
|
|
|
result = PKGMK_FAILURE;
|
|
|
|
} else {
|
|
|
|
// -- update
|
2010-05-18 15:13:25 -04:00
|
|
|
string pkgdest = getPkgmkPackageDir();
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( pkgdest != "" ) {
|
|
|
|
// TODO: don't manipulate pkgdir
|
|
|
|
pkgdir = pkgdest;
|
2006-04-04 14:50:25 -04:00
|
|
|
string message = "prt-get: Using PKGMK_PACKAGE_DIR: " + pkgdir;
|
|
|
|
if (parser->verbose() > 0) {
|
|
|
|
cout << message << endl;
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( m_config->writeLog() ) {
|
|
|
|
write( fdlog, message.c_str(), message.length() );
|
|
|
|
write( fdlog, "\n", 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// the following chdir is a noop if usePkgDest() returns false
|
|
|
|
if ( chdir( pkgdir.c_str() ) != 0 ) {
|
|
|
|
result = PKGDEST_ERROR;
|
|
|
|
} else {
|
|
|
|
cmd = PKGADD_DEFAULT_COMMAND;
|
|
|
|
if (m_config->addCommand() != "") {
|
|
|
|
cmd = m_config->addCommand();
|
|
|
|
}
|
|
|
|
|
|
|
|
args = "";
|
|
|
|
if (parser->installRoot() != "") {
|
|
|
|
args = "-r " + parser->installRoot() + " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( update ) {
|
|
|
|
args += "-u ";
|
|
|
|
}
|
|
|
|
if ( !parser->pkgaddArgs().empty() ) {
|
|
|
|
args += parser->pkgaddArgs() + " ";
|
|
|
|
}
|
|
|
|
args +=
|
|
|
|
package->name() + "#" +
|
|
|
|
package->version() + "-" +
|
2010-05-18 15:14:04 -04:00
|
|
|
package->release() + ".pkg.tar." + getPkgmkCompressionMode();
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
|
2006-04-04 14:50:25 -04:00
|
|
|
// - inform the user about what's happening
|
|
|
|
string fullCommand = commandName + ": " + cmd + " " + args;
|
|
|
|
string summary;
|
|
|
|
if (update) {
|
2006-04-13 03:04:14 -04:00
|
|
|
string from = m_pkgDB->getPackageVersion(package->name());
|
|
|
|
string to = package->version() + "-" + package->release();
|
|
|
|
if (from == to) {
|
2006-04-14 04:34:17 -04:00
|
|
|
summary = commandName + ": " + "reinstalling " +
|
2006-04-13 03:04:14 -04:00
|
|
|
package->name() + " " + to;
|
|
|
|
} else {
|
2006-04-14 04:34:17 -04:00
|
|
|
summary = commandName + ": " + "updating " +
|
2006-04-13 03:04:14 -04:00
|
|
|
package->name() + " from " + from + " to " + to;
|
|
|
|
}
|
2006-04-04 14:50:25 -04:00
|
|
|
} else {
|
2006-04-14 04:34:17 -04:00
|
|
|
summary = commandName + ": " + "installing " +
|
2006-04-04 14:50:25 -04:00
|
|
|
package->name() + " " +
|
|
|
|
package->version() + "-" + package->release();
|
2006-04-14 04:34:17 -04:00
|
|
|
}
|
|
|
|
|
2006-04-04 14:50:25 -04:00
|
|
|
// - print and log
|
|
|
|
cout << summary << endl;
|
|
|
|
if (parser->verbose() > 0) {
|
|
|
|
cout << fullCommand << endl;
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( m_config->writeLog() ) {
|
2006-04-07 03:49:13 -04:00
|
|
|
time_t endTime;
|
|
|
|
time(&endTime);
|
|
|
|
timestamp = ctime(&endTime);
|
|
|
|
timestamp = commandName + ": build done " + timestamp;
|
|
|
|
|
2006-04-04 14:50:25 -04:00
|
|
|
write( fdlog, summary.c_str(), summary.length() );
|
2006-04-07 03:49:13 -04:00
|
|
|
write( fdlog, "\n", 1 );
|
2006-04-04 14:50:25 -04:00
|
|
|
write( fdlog, fullCommand.c_str(), fullCommand.length() );
|
2005-11-09 16:43:05 -05:00
|
|
|
write( fdlog, "\n", 1 );
|
2006-04-07 03:49:13 -04:00
|
|
|
write( fdlog, timestamp.c_str(), timestamp.length());
|
|
|
|
write( fdlog, "\n", 1 );
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Process installProc( cmd, args, fdlog );
|
|
|
|
if ( installProc.executeShell() ) {
|
|
|
|
result = PKGADD_FAILURE;
|
|
|
|
} else {
|
|
|
|
// exec post install
|
|
|
|
if ((parser->execPostInstall() || m_config->runScripts() ) &&
|
|
|
|
stat((package->path() + "/" + package->name() +
|
|
|
|
"/" + "post-install").c_str(), &statData)
|
|
|
|
== 0) {
|
|
|
|
// Work around the pkgdir variable change
|
|
|
|
Process postProc( runscriptCommand,
|
|
|
|
package->path() + "/" + package->name()+
|
|
|
|
"/" + "post-install",
|
|
|
|
fdlog );
|
|
|
|
if (postProc.executeShell()) {
|
|
|
|
info.postState = FAILED;
|
|
|
|
} else {
|
|
|
|
info.postState = EXEC_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_config->writeLog() ) {
|
|
|
|
|
|
|
|
#ifdef USE_LOCKING
|
|
|
|
lockFile.unlock();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Close logfile
|
|
|
|
close ( fdlog );
|
2006-04-14 04:34:17 -04:00
|
|
|
|
|
|
|
if (m_config->removeLogOnSuccess() && !m_config->appendLog() &&
|
2006-04-04 12:22:35 -04:00
|
|
|
result == SUCCESS) {
|
|
|
|
unlink(logFile.c_str());
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Calculate dependencies for this transaction
|
|
|
|
\return true on success
|
|
|
|
*/
|
|
|
|
bool InstallTransaction::calculateDependencies()
|
|
|
|
{
|
|
|
|
if ( m_depCalced ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_depCalced = true;
|
|
|
|
if ( m_packages.empty() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-03-10 10:03:11 -05:00
|
|
|
vector<string> treeWalk;
|
2005-11-09 16:43:05 -05:00
|
|
|
list< pair<string, const Package*> >::const_iterator it =
|
|
|
|
m_packages.begin();
|
|
|
|
for ( ; it != m_packages.end(); ++it ) {
|
|
|
|
const Package* package = it->second;
|
|
|
|
if ( package ) {
|
2023-03-10 10:03:11 -05:00
|
|
|
checkDependencies( false, package );
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
list<int> indexList;
|
|
|
|
if ( ! m_resolver.resolve( indexList ) ) {
|
|
|
|
m_depCalced = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
list<int>::iterator lit = indexList.begin();
|
|
|
|
for ( ; lit != indexList.end(); ++lit ) {
|
|
|
|
m_depNameList.push_back( m_depList[*lit] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
recursive method to calculate dependencies
|
2023-03-10 10:03:11 -05:00
|
|
|
\param greedy (=true if any soft dependencies took us to the current node)
|
|
|
|
\param package, package for which we want to calculate dependencies
|
|
|
|
\param depends, index of the package \a package depends on (-1 for none)
|
2005-11-09 16:43:05 -05:00
|
|
|
*/
|
2023-03-10 10:03:11 -05:00
|
|
|
void InstallTransaction::checkDependencies( bool greedy,
|
|
|
|
const Package* package,
|
2005-11-09 16:43:05 -05:00
|
|
|
int depends )
|
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
bool newPackage = true;
|
2023-03-10 10:03:11 -05:00
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
for ( unsigned int i = 0; i < m_depList.size(); ++i ){
|
|
|
|
if ( m_depList[i] == package->name() ) {
|
|
|
|
index = i;
|
|
|
|
newPackage = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( index == -1 ) {
|
|
|
|
index = m_depList.size();
|
2023-03-10 10:03:11 -05:00
|
|
|
if (( not greedy ) or ( m_pkgDB->isInstalled(package->name(),false) )) {
|
2005-11-09 16:43:05 -05:00
|
|
|
m_depList.push_back( package->name() );
|
2023-03-10 10:03:11 -05:00
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
2023-03-10 10:03:11 -05:00
|
|
|
// did we already visit the current node when walking the tree?
|
|
|
|
// return to the caller if such a cycle is detected
|
|
|
|
for ( unsigned int i = 0; i < treeWalk.size(); ++i) {
|
|
|
|
if ( treeWalk[i] == package->name() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
treeWalk.push_back(package->name());
|
|
|
|
|
|
|
|
if ( depends == -1 ) {
|
2005-11-09 16:43:05 -05:00
|
|
|
// this just adds index to the dependency resolver
|
|
|
|
m_resolver.addDependency( index, index );
|
2023-03-10 10:03:11 -05:00
|
|
|
} else {
|
|
|
|
m_resolver.addDependency( index, depends );
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( newPackage ) {
|
|
|
|
if ( !package->dependencies().empty() ) {
|
|
|
|
list<string> deps;
|
|
|
|
split( package->dependencies(), ',', deps );
|
|
|
|
list<string>::iterator it = deps.begin();
|
|
|
|
for ( ; it != deps.end(); ++it ) {
|
|
|
|
string dep = *it;
|
|
|
|
if ( !dep.empty() ) {
|
|
|
|
string::size_type pos = dep.find_last_of( '/' );
|
|
|
|
if ( pos != string::npos && (pos+1) < dep.length() ) {
|
|
|
|
dep = dep.substr( pos + 1 );
|
|
|
|
}
|
|
|
|
const Package* p = m_repo->getPackage( dep );
|
|
|
|
if ( p ) {
|
2023-03-10 10:03:11 -05:00
|
|
|
checkDependencies( greedy, p, index );
|
2005-11-09 16:43:05 -05:00
|
|
|
} else {
|
|
|
|
m_missingPackages.
|
|
|
|
push_back( make_pair( dep, package->name() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-10 10:03:11 -05:00
|
|
|
}
|
|
|
|
if ( (m_config->followSoftdeps()) and (!package->optionals().empty()) ) {
|
|
|
|
list<string> softDeps;
|
|
|
|
split( package->optionals(), ',', softDeps );
|
|
|
|
list<string>::iterator it = softDeps.begin();
|
|
|
|
for ( ; it != softDeps.end(); ++it ) {
|
|
|
|
string softdep = *it;
|
|
|
|
if ( !softdep.empty() ) {
|
|
|
|
string::size_type pos = softdep.find_last_of( '/' );
|
|
|
|
if ( pos != string::npos && (pos+1) < softdep.length() ) {
|
|
|
|
softdep = softdep.substr( pos + 1 );
|
|
|
|
}
|
2023-03-12 07:37:16 -04:00
|
|
|
if ( m_pkgDB->isInstalled(softdep, false) or isRequested(softdep) ) {
|
2023-03-10 10:03:11 -05:00
|
|
|
const Package* p = m_repo->getPackage( softdep );
|
|
|
|
if ( p ) {
|
|
|
|
checkDependencies( true, p, index );
|
|
|
|
} else {
|
|
|
|
m_missingPackages.
|
|
|
|
push_back( make_pair( softdep, package->name() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
}
|
2023-03-10 10:03:11 -05:00
|
|
|
|
|
|
|
// reset the tree traversal history
|
|
|
|
treeWalk.pop_back();
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
2023-03-12 07:37:16 -04:00
|
|
|
/*!
|
|
|
|
Method to determine whether a package was passed on the command line
|
|
|
|
*/
|
|
|
|
bool InstallTransaction::isRequested(const string pname) {
|
|
|
|
list< pair<string, const Package*> >::iterator it = m_packages.begin();
|
|
|
|
for ( ; it != m_packages.end(); ++it ) {
|
|
|
|
if ( it->first == pname ) { return true; }
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
/*!
|
|
|
|
This method returns a list of packages which should be installed to
|
|
|
|
meet the requirements for the packages to be installed. Includes
|
|
|
|
the packages to be installed. The packages are in the correct order,
|
|
|
|
packages to be installed first come first :-)
|
|
|
|
|
|
|
|
\return a list of packages required for the transaction
|
|
|
|
*/
|
|
|
|
const list<string>& InstallTransaction::dependencies() const
|
|
|
|
{
|
|
|
|
return m_depNameList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
This method returns a list of packages which could not be installed
|
|
|
|
because they could not be found in the ports tree. The return value is
|
|
|
|
a pair, \a pair.first is package name and \a pair.second is the package
|
|
|
|
requiring \a pair.first.
|
|
|
|
|
|
|
|
\return packages missing in the ports tree
|
|
|
|
*/
|
|
|
|
const list< pair<string, string> >& InstallTransaction::missing() const
|
|
|
|
{
|
|
|
|
return m_missingPackages;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\return packages which were requested to be installed but are already
|
|
|
|
installed
|
|
|
|
*/
|
|
|
|
const list<string>& InstallTransaction::alreadyInstalledPackages() const
|
|
|
|
{
|
|
|
|
return m_alreadyInstalledPackages;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\return the packages which were installed in this transaction
|
|
|
|
*/
|
|
|
|
const list< pair<string, InstallTransaction::InstallInfo> >&
|
|
|
|
InstallTransaction::installedPackages() const
|
|
|
|
{
|
|
|
|
return m_installedPackages;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
calculate dependendencies for this package
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallResult
|
|
|
|
InstallTransaction::calcDependencies( )
|
|
|
|
{
|
|
|
|
if ( m_packages.empty() ) {
|
|
|
|
return NO_PACKAGE_GIVEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool validPackages = false;
|
|
|
|
list< pair<string, const Package*> >::iterator it = m_packages.begin();
|
|
|
|
for ( ; it != m_packages.end(); ++it ) {
|
|
|
|
if ( it->second ) {
|
|
|
|
validPackages = true;
|
|
|
|
} else {
|
|
|
|
// Note: moved here from calculateDependencies
|
|
|
|
m_missingPackages.push_back( make_pair( it->first, string("") ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !validPackages ) {
|
|
|
|
return PACKAGE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !calculateDependencies() ) {
|
|
|
|
return CYCLIC_DEPEND;
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-09-10 15:11:23 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* getPkgDest assumes that you're in the build directory already
|
|
|
|
*/
|
2010-05-18 15:13:25 -04:00
|
|
|
string InstallTransaction::getPkgmkSetting(const string& setting)
|
2006-09-27 11:41:25 -04:00
|
|
|
{
|
2010-05-18 15:13:25 -04:00
|
|
|
string value = "";
|
|
|
|
value = getPkgmkSettingFromFile(setting, "/etc/pkgmk.conf");
|
|
|
|
if (value.size() == 0) {
|
|
|
|
value = getPkgmkSettingFromFile(setting, "/usr/bin/pkgmk");
|
2006-09-27 11:41:25 -04:00
|
|
|
}
|
2006-10-19 04:34:44 -04:00
|
|
|
|
2010-05-18 15:13:25 -04:00
|
|
|
return value;
|
2006-09-27 11:41:25 -04:00
|
|
|
}
|
|
|
|
|
2010-05-18 15:13:25 -04:00
|
|
|
string InstallTransaction::getPkgmkSettingFromFile(const string& setting, const string& fileName)
|
2005-11-09 16:43:05 -05:00
|
|
|
{
|
2006-09-27 11:41:25 -04:00
|
|
|
FILE* fp = fopen(fileName.c_str(), "r");
|
|
|
|
if (!fp)
|
|
|
|
return "";
|
2006-10-19 04:34:44 -04:00
|
|
|
|
2006-09-27 11:41:25 -04:00
|
|
|
string candidate;
|
|
|
|
string s;
|
|
|
|
char line[256];
|
|
|
|
while (fgets(line, 256, fp)) {
|
|
|
|
s = StringHelper::stripWhiteSpace(line);
|
2010-05-18 15:13:25 -04:00
|
|
|
if (StringHelper::startsWith(s, setting + "=")) {
|
2006-09-27 11:41:25 -04:00
|
|
|
candidate = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
|
2010-05-18 15:13:25 -04:00
|
|
|
string value = "";
|
2006-09-27 11:41:25 -04:00
|
|
|
if (candidate.length() > 0) {
|
2010-05-18 15:13:25 -04:00
|
|
|
string cmd = "eval " + candidate + " && echo $" + setting;
|
2006-09-27 11:41:25 -04:00
|
|
|
FILE* p = popen(cmd.c_str(), "r");
|
|
|
|
if (p) {
|
|
|
|
fgets(line, 256, p);
|
2010-05-18 15:13:25 -04:00
|
|
|
value = StringHelper::stripWhiteSpace(line);
|
2023-06-09 14:32:02 -04:00
|
|
|
pclose(p);
|
2006-09-27 11:41:25 -04:00
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
2006-10-19 04:34:44 -04:00
|
|
|
|
2010-05-18 15:13:25 -04:00
|
|
|
return value;
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const list<string>& InstallTransaction::ignoredPackages() const
|
|
|
|
{
|
|
|
|
return m_ignoredPackages;
|
|
|
|
}
|
2006-09-27 11:41:25 -04:00
|
|
|
|
2010-05-18 15:13:25 -04:00
|
|
|
string InstallTransaction::getPkgmkPackageDir()
|
2006-09-27 11:41:25 -04:00
|
|
|
{
|
2010-05-18 15:13:25 -04:00
|
|
|
return getPkgmkSetting("PKGMK_PACKAGE_DIR");
|
2006-09-27 11:41:25 -04:00
|
|
|
}
|
2010-05-18 15:14:04 -04:00
|
|
|
|
|
|
|
string InstallTransaction::getPkgmkCompressionMode()
|
|
|
|
{
|
2017-01-21 06:13:16 -05:00
|
|
|
string value = getPkgmkSetting("PKGMK_COMPRESSION_MODE");
|
|
|
|
|
|
|
|
return value.size() ? value : "gz";
|
2010-05-18 15:14:04 -04:00
|
|
|
}
|