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"
|
2023-03-19 16:47:11 -04:00
|
|
|
#include "versioncomparator.h"
|
2005-11-09 16:43:05 -05:00
|
|
|
#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
|
|
|
|
*/
|
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
|
|
|
|
\return returns an InstallResult telling whether installation worked
|
|
|
|
*/
|
|
|
|
InstallTransaction::InstallResult
|
2023-03-19 16:47:11 -04:00
|
|
|
InstallTransaction::install( const ArgParser* parser )
|
2005-11-09 16:43:05 -05:00
|
|
|
{
|
|
|
|
if ( m_packages.empty() ) {
|
|
|
|
return NO_PACKAGE_GIVEN;
|
|
|
|
}
|
2006-04-04 12:22:35 -04:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
bool update;
|
|
|
|
const string forceRebuild = "-fr";
|
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;
|
|
|
|
}
|
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// Set the update flag if the package is installed and out of date,
|
|
|
|
// or if the user has forced a rebuild.
|
|
|
|
// Proceed to the next target if package is installed and up to date.
|
2023-08-22 09:12:05 -04:00
|
|
|
if ( m_pkgDB->isInstalled( it->first, false ) ) {
|
2023-03-19 16:47:11 -04:00
|
|
|
VersionComparator::COMP_RESULT
|
|
|
|
rpDiff = VersionComparator::compareVersions(
|
|
|
|
m_repo->getPackageVersion( package->name() ),
|
|
|
|
m_pkgDB->getPackageVersion( package->name() ) );
|
|
|
|
if ( rpDiff == VersionComparator::EQUAL &&
|
|
|
|
parser->pkgmkArgs().find(forceRebuild) == string::npos ) {
|
|
|
|
m_alreadyInstalledPackages.push_back( package->name() );
|
|
|
|
continue;
|
|
|
|
} else if ( (! m_config->preferHigher())
|
|
|
|
|| parser->strictDiff()
|
|
|
|
|| rpDiff == VersionComparator::GREATER
|
|
|
|
|| parser->pkgmkArgs().find(forceRebuild) !=
|
|
|
|
string::npos ) {
|
|
|
|
update = true;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
InstallTransaction::InstallResult result;
|
|
|
|
InstallInfo info( package->hasReadme() );
|
2023-06-23 14:08:28 -04:00
|
|
|
if ( parser->isTest() ) {
|
|
|
|
info.preState = ( package->hasPreInstall() &&
|
|
|
|
(parser->execPreInstall() || m_config->runScripts())
|
|
|
|
) ? DEFERRED : NONEXISTENT;
|
|
|
|
info.postState = ( package->hasPostInstall() &&
|
|
|
|
(parser->execPostInstall() || m_config->runScripts())
|
|
|
|
) ? DEFERRED : NONEXISTENT;
|
|
|
|
m_installedPackages.push_back( make_pair( package->path() + "/" + package->name(), info));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((result = installPackage( package, parser, update, info )) == SUCCESS) {
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-05-29 08:21:18 -04:00
|
|
|
m_installedPackages.push_back( make_pair( package->path() + "/" + package->name(), info));
|
2005-11-09 16:43:05 -05:00
|
|
|
} else {
|
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// log failures and pkgdest errors are critical,
|
|
|
|
// don't proceed to the next install target if encountered
|
2005-11-09 16:43:05 -05:00
|
|
|
if ( result == LOG_DIR_FAILURE ||
|
|
|
|
result == LOG_FILE_FAILURE ||
|
|
|
|
result == NO_LOG_FILE ||
|
|
|
|
result == CANT_LOCK_LOG_FILE ||
|
|
|
|
result == PKGDEST_ERROR ) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-05-29 08:21:18 -04:00
|
|
|
m_installErrors.push_back( make_pair(package->path() + "/" + 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 )
|
2023-03-19 16:47:11 -04:00
|
|
|
const {
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// - initial information about the package to be built
|
2006-04-14 04:34:17 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
string portdir = package->path() + "/" + package->name();
|
|
|
|
chdir( portdir.c_str() );
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-05-29 08:21:18 -04:00
|
|
|
string runscriptCommand = "/bin/sh";
|
2005-11-09 16:43:05 -05:00
|
|
|
if (m_config->runscriptCommand() != "") {
|
|
|
|
runscriptCommand = m_config->runscriptCommand();
|
|
|
|
}
|
2023-05-29 08:21:18 -04:00
|
|
|
if (parser->installRoot() != "") {
|
|
|
|
runscriptCommand = "chroot " + parser->installRoot() + " "
|
|
|
|
+ runscriptCommand;
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
|
|
|
// -- pre-install
|
2023-03-19 16:47:11 -04:00
|
|
|
struct stat statData; struct stat fstatData;
|
2005-11-09 16:43:05 -05:00
|
|
|
if ((parser->execPreInstall() || m_config->runScripts()) &&
|
2023-06-19 14:54:06 -04:00
|
|
|
stat((parser->installRoot() + portdir + "/pre-install").c_str(),
|
|
|
|
&statData) == 0) {
|
2005-11-09 16:43:05 -05:00
|
|
|
Process preProc( runscriptCommand,
|
2023-03-19 16:47:11 -04:00
|
|
|
portdir + "/pre-install",
|
2005-11-09 16:43:05 -05:00
|
|
|
fdlog );
|
|
|
|
if (preProc.executeShell()) {
|
|
|
|
info.preState = FAILED;
|
|
|
|
} else {
|
|
|
|
info.preState = EXEC_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- build
|
2023-06-08 11:42:58 -04:00
|
|
|
string pkgdest = m_config->packageDir();
|
|
|
|
string builtPkg = package->name() + "#" + package->version() + "-" +
|
|
|
|
package->release() + ".pkg.tar." + m_config->compressionMode();
|
2023-03-19 16:47:11 -04:00
|
|
|
string builtPkgPath = ( pkgdest != "" ) ? pkgdest + "/" + builtPkg :
|
|
|
|
portdir + "/" + builtPkg ;
|
2005-11-09 16:43:05 -05:00
|
|
|
string cmd = PKGMK_DEFAULT_COMMAND;
|
|
|
|
if (m_config->makeCommand() != "") {
|
|
|
|
cmd = m_config->makeCommand();
|
|
|
|
}
|
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// skip the build if a package exists newer than Pkgfile
|
|
|
|
// (e.g., created by running pkgmk manually)
|
|
|
|
if ( stat(builtPkgPath.c_str(), &statData) +
|
|
|
|
stat((portdir + "/Pkgfile").c_str(), &fstatData) == 0) {
|
|
|
|
time_t pkgMtime = statData.st_mtime;
|
|
|
|
time_t pfMtime = fstatData.st_mtime;
|
|
|
|
if ( difftime(pkgMtime,pfMtime) > 0 ) { cmd = "/bin/true"; }
|
|
|
|
}
|
|
|
|
|
2005-11-09 16:43:05 -05:00
|
|
|
string args = "-d " + parser->pkgmkArgs();
|
|
|
|
Process makeProc( cmd, args, fdlog );
|
|
|
|
if ( makeProc.executeShell() ) {
|
|
|
|
result = PKGMK_FAILURE;
|
|
|
|
} else {
|
2023-03-19 16:47:11 -04:00
|
|
|
string message = ( pkgdest == "" ) ? "" :
|
|
|
|
commandName + ": Using PKGMK_PACKAGE_DIR " + pkgdest;
|
2006-04-04 14:50:25 -04:00
|
|
|
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 );
|
|
|
|
}
|
2023-03-19 16:47:11 -04:00
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// no need to chdir if we provide absolute paths to pkgadd
|
|
|
|
cmd = PKGADD_DEFAULT_COMMAND;
|
|
|
|
if (m_config->addCommand() != "") {
|
|
|
|
cmd = m_config->addCommand();
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
args = "";
|
|
|
|
if (parser->installRoot() != "") {
|
|
|
|
args = "-r " + parser->installRoot() + " ";
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
if ( update ) {
|
|
|
|
args += "-u ";
|
|
|
|
}
|
|
|
|
if ( !parser->pkgaddArgs().empty() ) {
|
|
|
|
args += parser->pkgaddArgs() + " ";
|
|
|
|
}
|
|
|
|
args += builtPkgPath;
|
2006-04-14 04:34:17 -04:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// - inform the user about what's happening
|
|
|
|
string fullCommand = commandName + ": " + cmd + args;
|
|
|
|
string summary;
|
|
|
|
if (update) {
|
|
|
|
string from = m_pkgDB->getPackageVersion(package->name());
|
|
|
|
string to = m_repo->getPackageVersion(package->name());
|
|
|
|
if (from == to) {
|
|
|
|
summary = commandName + ": " + "reinstalling " +
|
|
|
|
package->name() + " " + to;
|
|
|
|
} else {
|
|
|
|
summary = commandName + ": " + "updating " +
|
|
|
|
package->name() + " from " + from + " to " + to;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
summary = commandName + ": " + "installing " + package->name() +
|
|
|
|
" " + package->version() + "-" + package->release();
|
|
|
|
}
|
2006-04-07 03:49:13 -04:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
// - print and log
|
|
|
|
cout << summary << endl;
|
|
|
|
if (parser->verbose() > 0) {
|
|
|
|
cout << fullCommand << endl;
|
|
|
|
}
|
|
|
|
if ( m_config->writeLog() ) {
|
|
|
|
time_t endTime;
|
|
|
|
time(&endTime);
|
|
|
|
timestamp = ctime(&endTime);
|
|
|
|
timestamp = commandName + ": build done " + timestamp;
|
|
|
|
|
|
|
|
write( fdlog, summary.c_str(), summary.length() );
|
|
|
|
write( fdlog, "\n", 1 );
|
|
|
|
write( fdlog, fullCommand.c_str(), fullCommand.length() );
|
|
|
|
write( fdlog, "\n", 1 );
|
|
|
|
write( fdlog, timestamp.c_str(), timestamp.length());
|
|
|
|
write( fdlog, "\n", 1 );
|
|
|
|
}
|
2005-11-09 16:43:05 -05:00
|
|
|
|
2023-03-19 16:47:11 -04:00
|
|
|
Process installProc( cmd, args, fdlog );
|
|
|
|
if ( installProc.executeShell() ) {
|
|
|
|
result = PKGADD_FAILURE;
|
|
|
|
} else {
|
|
|
|
// exec post install
|
|
|
|
if ((parser->execPostInstall() || m_config->runScripts() ) &&
|
2023-06-19 14:54:06 -04:00
|
|
|
stat((parser->installRoot() + portdir + "/post-install").c_str(),
|
|
|
|
&statData) == 0) {
|
2023-03-19 16:47:11 -04:00
|
|
|
Process postProc( runscriptCommand,
|
|
|
|
portdir + "/post-install", fdlog );
|
|
|
|
if (postProc.executeShell()) {
|
|
|
|
info.postState = FAILED;
|
|
|
|
} else {
|
|
|
|
info.postState = EXEC_SUCCESS;
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-08-22 09:12:05 -04:00
|
|
|
list<pair<string, const Package*>>::const_iterator it = m_packages.begin();
|
2005-11-09 16:43:05 -05:00
|
|
|
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-08-22 09:12:05 -04:00
|
|
|
if ( ( not greedy ) or (isRequired( package->name() )) ) {
|
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;
|
2023-08-22 09:12:05 -04:00
|
|
|
if ( dep.empty() ) { continue; }
|
|
|
|
const Package* p = m_repo->getPackage( dep );
|
|
|
|
if ( p ) {
|
|
|
|
checkDependencies( greedy, p, index );
|
|
|
|
} else {
|
|
|
|
m_missingPackages.
|
|
|
|
push_back( make_pair( dep, package->name() ) );
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
}
|
2023-03-10 10:03:11 -05:00
|
|
|
}
|
|
|
|
if ( (m_config->followSoftdeps()) and (!package->optionals().empty()) ) {
|
2023-08-22 09:12:05 -04:00
|
|
|
list<string> optionals;
|
|
|
|
split( package->optionals(), ',', optionals );
|
|
|
|
list<string>::iterator it = optionals.begin();
|
|
|
|
for ( ; it != optionals.end(); ++it ) {
|
2023-03-10 10:03:11 -05:00
|
|
|
string softdep = *it;
|
2023-08-22 09:12:05 -04:00
|
|
|
if ( softdep.empty() ) { continue; }
|
|
|
|
if ( isRequired(softdep) ) {
|
|
|
|
const Package* p = m_repo->getPackage( softdep );
|
|
|
|
if ( p ) {
|
|
|
|
checkDependencies( true, p, index );
|
|
|
|
} else {
|
|
|
|
m_missingPackages.
|
|
|
|
push_back( make_pair( softdep, package->name() ) );
|
2023-03-10 10:03:11 -05:00
|
|
|
}
|
2023-08-22 09:12:05 -04:00
|
|
|
}
|
2023-03-10 10:03:11 -05:00
|
|
|
}
|
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-19 16:47:11 -04:00
|
|
|
/*!
|
2023-08-22 09:12:05 -04:00
|
|
|
Method to determine whether a soft dependency should be part of the transaction
|
2023-03-19 16:47:11 -04:00
|
|
|
*/
|
2023-08-22 09:12:05 -04:00
|
|
|
bool InstallTransaction::isRequired(const string &pname) {
|
|
|
|
list<pair<string, const Package*>>::iterator it = m_packages.begin();
|
2023-03-19 16:47:11 -04:00
|
|
|
for ( ; it != m_packages.end(); ++it ) {
|
2023-08-22 09:12:05 -04:00
|
|
|
if ( pname == it->first ) { return true; }
|
2023-03-19 16:47:11 -04:00
|
|
|
}
|
|
|
|
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
|
|
|
|
*/
|
2023-03-19 16:47:11 -04:00
|
|
|
bool InstallTransaction::calcDependencies( )
|
2005-11-09 16:43:05 -05:00
|
|
|
{
|
|
|
|
if ( m_packages.empty() ) {
|
2023-03-19 16:47:11 -04:00
|
|
|
cout << "No packages given for this transaction" << endl;
|
|
|
|
return false;
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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("") ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 07:52:08 -04:00
|
|
|
if ( validPackages and (!calculateDependencies()) ) {
|
2023-03-19 16:47:11 -04:00
|
|
|
cout << "Could not resolve dependencies for this transaction" << endl;
|
|
|
|
return false;
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
2023-03-19 16:47:11 -04:00
|
|
|
return true;
|
2005-11-09 16:43:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const list<string>& InstallTransaction::ignoredPackages() const
|
|
|
|
{
|
|
|
|
return m_ignoredPackages;
|
|
|
|
}
|