2016-02-15 18:26:05 +01:00
# include " ./manager.h "
2015-09-07 19:36:45 +02:00
# include "./utilities.h"
# include "./config.h"
2015-09-21 22:16:19 +02:00
# include "./alpmdatabase.h"
2015-08-10 22:46:01 +02:00
2015-09-07 19:36:45 +02:00
# include "../network/userrepository.h"
2015-09-04 14:37:01 +02:00
2015-08-10 22:46:01 +02:00
# include <c++utilities/io/inifile.h>
# include <c++utilities/conversion/stringconversion.h>
2015-09-04 14:37:01 +02:00
# include <c++utilities/misc/memory.h>
2015-08-10 22:46:01 +02:00
# include <QList>
# include <QSysInfo>
2015-08-19 02:13:28 +02:00
# include <QMutexLocker>
2015-09-11 21:59:47 +02:00
# include <QStringBuilder>
# include <QFile>
# include <QDataStream>
2016-01-18 20:34:29 +01:00
# include <QTimer>
2016-02-14 23:48:43 +01:00
# include <QFileInfo>
# include <QtConcurrent>
2015-09-05 17:25:05 +02:00
2015-08-10 22:46:01 +02:00
# include <fstream>
# include <iostream>
# include <unordered_map>
# include <algorithm>
using namespace std ;
using namespace IoUtilities ;
using namespace ConversionUtilities ;
2015-09-05 17:25:05 +02:00
namespace RepoIndex {
2015-08-10 22:46:01 +02:00
2015-09-04 14:37:01 +02:00
/*!
* \ cond
*/
2016-02-14 23:48:43 +01:00
constexpr auto defaultSigLevel = SignatureLevel : : Package | SignatureLevel : : PackageOptional
| SignatureLevel : : Database | SignatureLevel : : DatabaseOptional ;
2015-08-10 22:46:01 +02:00
2015-09-04 14:37:01 +02:00
inline ostream & operator < < ( ostream & stream , const QString & str )
{
stream < < str . toLocal8Bit ( ) . data ( ) ;
return stream ;
}
/*!
* \ endcond
*/
2015-08-10 22:46:01 +02:00
/*!
* \ brief The Manager class helps accessing ALPM .
*
* - It queries the ALPM for database and package information .
* - It serializes the information as JSON objects used by the network classes and the web interface .
*/
/*!
* \ brief Creates a new manager class ; initializes a new ALPM handle .
* \ param rootdir Specifies the root directory .
* \ param dbpath Specifies the database directory .
*/
2015-08-19 02:13:28 +02:00
Manager : : Manager ( const Config & config ) :
2015-08-10 22:46:01 +02:00
m_config ( config ) ,
2015-09-11 21:59:47 +02:00
m_writeCacheBeforeGone ( true ) ,
2015-08-10 22:46:01 +02:00
m_sigLevel ( defaultSigLevel ) ,
2016-02-14 23:48:43 +01:00
m_localFileSigLevel ( SignatureLevel : : UseDefault )
2015-08-10 22:46:01 +02:00
{
2016-02-14 23:48:43 +01:00
addLocalDatabase ( ) ;
2015-09-04 14:37:01 +02:00
if ( config . isAurEnabled ( ) ) {
2016-02-20 03:00:34 +01:00
m_userRepo = make_unique < UserRepository > ( ) ;
2015-08-10 22:46:01 +02:00
}
}
/*!
* \ brief Releases the associated ALPM handle .
*/
Manager : : ~ Manager ( )
{
2015-09-11 21:59:47 +02:00
if ( m_writeCacheBeforeGone ) {
writeCache ( ) ;
}
2016-02-14 23:48:43 +01:00
removeAllDatabases ( ) ;
2015-08-10 22:46:01 +02:00
}
/*!
2015-09-05 17:25:05 +02:00
* \ brief Returns the first package with the specified name from the specified database .
2015-08-10 22:46:01 +02:00
*/
2015-09-05 17:25:05 +02:00
AlpmPackage * Manager : : packageFromDatabase ( const QString & dbName , const QString & pkgName )
2015-08-10 22:46:01 +02:00
{
2015-09-05 17:25:05 +02:00
if ( auto * db = databaseByName ( dbName ) ) {
2015-09-04 14:37:01 +02:00
return static_cast < AlpmPackage * > ( db - > packageByName ( pkgName ) ) ;
} else {
return nullptr ;
}
}
/*!
2015-09-05 17:25:05 +02:00
* \ brief Returns the first package with the specified name from the specified database .
2015-09-04 14:37:01 +02:00
*/
2015-09-05 17:25:05 +02:00
const AlpmPackage * Manager : : packageFromDatabase ( const QString & dbName , const QString & pkgName ) const
2015-09-04 14:37:01 +02:00
{
2015-09-05 17:25:05 +02:00
if ( const auto * db = databaseByName ( dbName ) ) {
2015-09-04 14:37:01 +02:00
return static_cast < const AlpmPackage * > ( db - > packageByName ( pkgName ) ) ;
} else {
return nullptr ;
}
}
/*!
2015-09-05 17:25:05 +02:00
* \ brief Returns the first package with the specified \ a name from one of the sync databases .
2015-09-04 14:37:01 +02:00
*/
2015-09-05 17:25:05 +02:00
AlpmPackage * Manager : : packageFromSyncDatabases ( const QString & pkgName )
2015-09-04 14:37:01 +02:00
{
2015-12-08 18:59:17 +01:00
for ( const auto & dbEntry : m_syncDbs ) {
if ( auto * pkg = dbEntry - > packageByName ( pkgName ) ) {
2015-09-04 14:37:01 +02:00
return static_cast < AlpmPackage * > ( pkg ) ;
}
}
return nullptr ;
}
/*!
2015-09-05 17:25:05 +02:00
* \ brief Returns the first package with the specified \ a name from one of the sync databases .
2015-09-04 14:37:01 +02:00
*/
2015-09-05 17:25:05 +02:00
const AlpmPackage * Manager : : packageFromSyncDatabases ( const QString & pkgName ) const
2015-09-04 14:37:01 +02:00
{
2015-12-08 18:59:17 +01:00
for ( const auto & dbEntry : m_syncDbs ) {
if ( const auto * pkg = dbEntry - > packageByName ( pkgName ) ) {
2015-09-04 14:37:01 +02:00
return static_cast < const AlpmPackage * > ( pkg ) ;
2015-08-10 22:46:01 +02:00
}
}
2015-09-04 14:37:01 +02:00
return nullptr ;
2015-08-10 22:46:01 +02:00
}
2015-09-05 17:25:05 +02:00
/*!
2015-12-08 00:24:45 +01:00
* \ brief Returns the first package satisfiing the specified dependency from one of the available package sources ( excluding the local database
* and sources requirering requests such as the AUR ) .
2015-09-05 17:25:05 +02:00
*/
Package * Manager : : packageProviding ( const Dependency & dependency )
{
2015-12-08 18:59:17 +01:00
for ( auto & dbEntry : m_syncDbs ) {
QReadLocker locker ( dbEntry - > lock ( ) ) ;
if ( auto * pkg = dbEntry - > packageProviding ( dependency ) ) {
2015-09-05 17:25:05 +02:00
return pkg ;
}
}
return nullptr ;
}
/*!
* \ brief Returns the first package satisfiing the specified dependency from one of the available package sources ( excluding the local database
* and sources requirering requests such as the AUR ) .
*/
const Package * Manager : : packageProviding ( const Dependency & dependency ) const
{
2015-12-08 18:59:17 +01:00
for ( const auto & dbEntry : m_syncDbs ) {
QReadLocker locker ( dbEntry - > lock ( ) ) ;
if ( const auto * pkg = dbEntry - > packageProviding ( dependency ) ) {
2015-09-05 17:25:05 +02:00
return pkg ;
}
}
return nullptr ;
}
2015-08-10 22:46:01 +02:00
/*!
* \ brief Returns the last value with the specified \ a key in the specified multimap .
*/
const string & lastValue ( const multimap < string , string > & mm , const string & key )
{
static const string defaultValue ;
const auto i = find_if ( mm . crbegin ( ) , mm . crend ( ) , [ & key ] ( const pair < string , string > & i ) {
return i . first = = key ;
} ) ;
return i ! = mm . crend ( ) ? i - > second : defaultValue ;
}
/*!
* \ brief Parses a " SigLevel " denotation from pacman config file .
*/
2016-02-14 23:48:43 +01:00
SignatureLevel Manager : : parseSigLevel ( const string & sigLevelStr )
2015-08-10 22:46:01 +02:00
{
2016-02-14 23:48:43 +01:00
SignatureLevel sigLevel = defaultSigLevel ;
2015-08-10 22:46:01 +02:00
// split sig level denotation into parts
const auto parts = splitString < list < string > > ( sigLevelStr , " " ) ;
for ( const auto & part : parts ) {
// determine whether part affect packages, databases or both
bool package = true , db = true ;
const char * partStart = part . data ( ) ;
if ( ! strncmp ( partStart , " Package " , 7 ) ) {
db = false ; // package only part
partStart + = 7 ;
} else if ( ! strncmp ( partStart , " Database " , 8 ) ) {
package = false ; // db only part
partStart + = 8 ;
}
// set sig level according part
if ( ! strcmp ( partStart , " Never " ) ) {
if ( package ) {
2016-02-14 23:48:43 +01:00
sigLevel & = ~ SignatureLevel : : Package ;
2015-08-10 22:46:01 +02:00
}
if ( db ) {
2016-02-14 23:48:43 +01:00
sigLevel & = ~ SignatureLevel : : Database ;
2015-08-10 22:46:01 +02:00
}
} else if ( ! strcmp ( partStart , " Optional " ) ) {
if ( package ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : Package | SignatureLevel : : PackageOptional ;
2015-08-10 22:46:01 +02:00
}
if ( db ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : Database | SignatureLevel : : DatabaseOptional ;
2015-08-10 22:46:01 +02:00
}
} else if ( ! strcmp ( partStart , " Required " ) ) {
if ( package ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : Package ;
sigLevel & = ~ SignatureLevel : : PackageOptional ;
2015-08-10 22:46:01 +02:00
}
if ( db ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : Database ;
sigLevel & = ~ SignatureLevel : : DatabaseOptional ;
2015-08-10 22:46:01 +02:00
}
} else if ( ! strcmp ( partStart , " TrustedOnly " ) ) {
if ( package ) {
2016-02-14 23:48:43 +01:00
sigLevel & = ~ ( SignatureLevel : : PackageMarginalOk | SignatureLevel : : PackageUnknownOk ) ;
2015-08-10 22:46:01 +02:00
}
if ( db ) {
2016-02-14 23:48:43 +01:00
sigLevel & = ~ ( SignatureLevel : : DatabaseMarginalOk | SignatureLevel : : DatabaseUnknownOk ) ;
2015-08-10 22:46:01 +02:00
}
} else if ( ! strcmp ( partStart , " TrustAll " ) ) {
if ( package ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : PackageMarginalOk | SignatureLevel : : PackageUnknownOk ;
2015-08-10 22:46:01 +02:00
}
if ( db ) {
2016-02-14 23:48:43 +01:00
sigLevel | = SignatureLevel : : DatabaseMarginalOk | SignatureLevel : : DatabaseUnknownOk ;
2015-08-10 22:46:01 +02:00
}
} else {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Warning: Invalid value \" " < < part < < " \" for \" SigLevel \" in pacman config file will be ignored. " < < endl ;
2015-08-10 22:46:01 +02:00
}
}
return sigLevel ;
}
/*!
* \ brief Parses a " Usage " denotation from pacman config file .
*/
2016-02-14 23:48:43 +01:00
RepositoryUsage Manager : : parseUsage ( const string & usageStr )
2015-08-10 22:46:01 +02:00
{
2016-02-14 23:48:43 +01:00
RepositoryUsage usage = RepositoryUsage : : None ;
const auto parts = splitString < list < string > > ( usageStr , " " , EmptyPartsTreat : : Omit ) ;
2015-08-10 22:46:01 +02:00
for ( const auto & part : parts ) {
if ( part = = " Sync " ) {
2016-02-14 23:48:43 +01:00
usage | = RepositoryUsage : : Sync ;
2015-08-10 22:46:01 +02:00
} else if ( part = = " Search " ) {
2016-02-14 23:48:43 +01:00
usage | = RepositoryUsage : : Search ;
2015-08-10 22:46:01 +02:00
} else if ( part = = " Install " ) {
2016-02-14 23:48:43 +01:00
usage | = RepositoryUsage : : Install ;
2015-08-10 22:46:01 +02:00
} else if ( part = = " Upgrade " ) {
2016-02-14 23:48:43 +01:00
usage | = RepositoryUsage : : Upgrade ;
2015-08-10 22:46:01 +02:00
} else {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Warning: Invalid value \" " < < part < < " \" for \" Usage \" in pacman config file will be ignored. " < < endl ;
2015-08-10 22:46:01 +02:00
}
}
2016-02-14 23:48:43 +01:00
return usage ! = RepositoryUsage : : None ? usage : RepositoryUsage : : All ;
2015-08-10 22:46:01 +02:00
}
/*!
2016-02-14 23:48:43 +01:00
* \ brief Adds sync databases listed in the Pacman config file . Also reads the cache dir .
2015-08-10 22:46:01 +02:00
*/
2016-02-14 23:48:43 +01:00
void Manager : : addDataBasesFromPacmanConfig ( )
2015-08-10 22:46:01 +02:00
{
// open config file and parse as ini
try {
IniFile configIni ;
{
fstream configFile ;
configFile . exceptions ( ios_base : : failbit | ios_base : : badbit ) ;
configFile . open ( m_config . pacmanConfFile ( ) . toLocal8Bit ( ) . data ( ) , ios_base : : in ) ;
configIni . parse ( configFile ) ;
}
// determine current cpu archtitecture (required for server URLs)
static const string sysArch ( QSysInfo : : currentCpuArchitecture ( ) . toStdString ( ) ) ;
2016-02-14 23:48:43 +01:00
string arch ( sysArch ) ;
2015-08-10 22:46:01 +02:00
const auto & config = configIni . data ( ) ;
// read relevant options
static const string sigLevelKey ( " SigLevel " ) ;
static const string usageKey ( " Usage " ) ;
2016-02-14 23:48:43 +01:00
SignatureLevel globalSigLevel = defaultSigLevel ;
2015-09-21 22:16:19 +02:00
for ( auto & scope : config ) {
if ( scope . first = = " options " ) {
// iterate through all "config" scopes (just to cover the case that there are multiple "options" scopes)
const auto & options = scope . second ;
const auto & specifiedArch = lastValue ( options , " Architecture " ) ;
if ( ! specifiedArch . empty ( ) & & specifiedArch ! = " auto " ) {
arch = specifiedArch ;
}
const auto & specifiedDir = lastValue ( options , " CacheDir " ) ;
if ( ! specifiedDir . empty ( ) ) {
m_pacmanCacheDir = QString : : fromStdString ( specifiedDir ) ;
}
globalSigLevel = parseSigLevel ( lastValue ( options , sigLevelKey ) ) ;
2015-08-10 22:46:01 +02:00
}
}
// register sync databases
unordered_map < string , IniFile > includedInis ;
for ( const auto & scope : config ) {
if ( scope . first ! = " options " ) {
// read and validate database name
QString dbName = QString : : fromLocal8Bit ( scope . first . c_str ( ) ) ;
2015-08-19 02:13:28 +02:00
if ( dbName . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Error: Unable to add database from pacman config: The database name mustn't be \" local \" because this name is reserved for the local database. " < < endl ;
2015-08-19 02:13:28 +02:00
} else if ( dbName . startsWith ( QLatin1String ( " aur " ) , Qt : : CaseInsensitive ) ) {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Error: Unable to add database from pacman config: The database name mustn't start with \" aur \" because this name is reserved for the Arch Linux User Repository. " < < endl ;
2015-12-08 18:59:17 +01:00
} else if ( m_syncDbMap . count ( dbName ) ) {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Error: Unable to add database from pacman config: Database names must be unique. Ignoring second occurance of database \" " < < scope . first < < " \" . " < < endl ;
2015-08-10 22:46:01 +02:00
} else {
// read sig level and usage
const auto & sigLevelStr = lastValue ( scope . second , sigLevelKey ) ;
2016-02-14 23:48:43 +01:00
SignatureLevel sigLevel = sigLevelStr . empty ( ) ? globalSigLevel : parseSigLevel ( sigLevelStr ) ;
RepositoryUsage usage = parseUsage ( lastValue ( scope . second , usageKey ) ) ;
// add sync db to internal map (use as index size + 1 because the local database has index 0)
2016-02-15 18:26:05 +01:00
m_syncDbs . emplace_back ( make_unique < AlpmDatabase > ( dbName , findDatabasePath ( dbName , false , false ) , usage , sigLevel , m_syncDbs . size ( ) + 1 ) ) ;
2016-02-14 23:48:43 +01:00
AlpmDatabase * emplacedDb = m_syncDbs . back ( ) . get ( ) ;
m_syncDbMap . emplace ( dbName , emplacedDb ) ;
2016-02-15 18:26:05 +01:00
cerr < < shchar < < " Added [ " < < dbName < < " ] " < < endl ;
2016-02-14 23:48:43 +01:00
if ( usage & RepositoryUsage : : Upgrade ) {
// -> db is used to upgrade local database
localDataBase ( ) - > upgradeSources ( ) < < emplacedDb ;
}
// add servers
for ( auto range = scope . second . equal_range ( " Server " ) ; range . first ! = range . second ; + + range . first ) {
string url = range . first - > second ;
findAndReplace < string > ( url , " $repo " , scope . first ) ;
findAndReplace < string > ( url , " $arch " , arch ) ;
emplacedDb - > serverUrls ( ) < < Utilities : : qstr ( url ) ;
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
2016-02-15 18:26:05 +01:00
cerr < < shchar < < " Added server: " < < url < < endl ;
2015-08-10 22:46:01 +02:00
}
2016-02-14 23:48:43 +01:00
}
// add included servers / parse mirror list
for ( auto range = scope . second . equal_range ( " Include " ) ; range . first ! = range . second ; + + range . first ) {
const auto & path = range . first - > second ;
auto & includedIni = includedInis [ path ] ;
if ( includedIni . data ( ) . empty ( ) ) {
try {
fstream includedFile ;
includedFile . exceptions ( ios_base : : failbit | ios_base : : badbit ) ;
includedFile . open ( path , ios_base : : in ) ;
includedIni . parse ( includedFile ) ;
} catch ( const ios_base : : failure & ) {
cerr < < shchar < < " Error: An IO exception occured when parsing the included file \" " < < path < < " \" . " < < endl ;
2015-08-19 02:13:28 +02:00
}
2015-08-10 22:46:01 +02:00
}
2016-02-14 23:48:43 +01:00
try {
for ( auto & scope : includedIni . data ( ) ) {
if ( scope . first . empty ( ) ) {
for ( auto range = scope . second . equal_range ( " Server " ) ; range . first ! = range . second ; + + range . first ) {
string url = range . first - > second ;
findAndReplace < string > ( url , " $repo " , scope . first ) ;
findAndReplace < string > ( url , " $arch " , arch ) ;
emplacedDb - > serverUrls ( ) < < Utilities : : qstr ( url ) ;
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
2016-02-15 18:26:05 +01:00
cerr < < shchar < < " Added server: " < < url < < endl ;
2015-09-21 22:16:19 +02:00
}
2015-08-19 02:13:28 +02:00
}
2015-08-10 22:46:01 +02:00
}
}
2016-02-14 23:48:43 +01:00
} catch ( const out_of_range & ) {
cerr < < shchar < < " Warning: Included file \" " < < path < < " \" has no values. " < < endl ;
2015-08-10 22:46:01 +02:00
}
}
}
}
}
} catch ( const ios_base : : failure & ) {
2015-08-19 02:13:28 +02:00
throw ios_base : : failure ( " Error: An IO exception occured when parsing the config file. " ) ;
}
}
/*!
2016-02-14 23:48:43 +01:00
* \ brief Adds sync databases listed in the repository index configuration .
2015-08-19 02:13:28 +02:00
*/
2016-02-14 23:48:43 +01:00
void Manager : : addDatabasesFromRepoIndexConfig ( )
2015-08-19 02:13:28 +02:00
{
2015-09-04 14:37:01 +02:00
// check whether an entry already exists, if not create a new one
2015-08-19 02:13:28 +02:00
for ( const RepoEntry & repoEntry : m_config . repoEntries ( ) ) {
2015-09-05 17:25:05 +02:00
AlpmDatabase * syncDb = nullptr ;
2015-08-19 02:13:28 +02:00
try {
2015-12-08 18:59:17 +01:00
syncDb = m_syncDbMap . at ( repoEntry . name ( ) ) ;
2015-09-21 22:16:19 +02:00
cerr < < shchar < < " Applying config for database [ " < < syncDb - > name ( ) < < ' ] ' < < endl ;
2016-02-14 23:48:43 +01:00
if ( ! repoEntry . databasePath ( ) . isEmpty ( ) ) {
syncDb - > setDatabasePath ( repoEntry . databasePath ( ) ) ;
2015-08-19 02:13:28 +02:00
}
2016-02-14 23:48:43 +01:00
if ( repoEntry . sigLevel ( ) ! = SignatureLevel : : UseDefault ) {
syncDb - > setSigLevel ( repoEntry . sigLevel ( ) ) ;
2015-08-19 02:13:28 +02:00
}
syncDb - > setPackagesDirectory ( repoEntry . packageDir ( ) ) ;
syncDb - > setSourcesDirectory ( repoEntry . sourceDir ( ) ) ;
} catch ( const out_of_range & ) {
if ( repoEntry . name ( ) . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Error: Unable to add database from repo index config: The database name mustn't be \" local \" because this name is reserved for the local database. " < < endl ;
2015-08-19 02:13:28 +02:00
} else if ( repoEntry . name ( ) . startsWith ( QLatin1String ( " aur " ) , Qt : : CaseInsensitive ) ) {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Error: Unable to add database from repo index config: The database name mustn't start with \" aur \" because this name is reserved for the Arch Linux User Repository. " < < endl ;
2015-08-19 02:13:28 +02:00
} else {
2016-02-14 23:48:43 +01:00
// determine path of db file
// -> currently just use the file from pacman dir, TODO: download syncdata base
QString dbPath ;
if ( repoEntry . databasePath ( ) . isEmpty ( ) ) {
2016-02-15 18:26:05 +01:00
// no path specified -> use defaults
dbPath = findDatabasePath ( repoEntry . name ( ) , ! repoEntry . maxDatabaseAge ( ) . isNull ( ) , true ) ;
2016-02-14 23:48:43 +01:00
} else {
dbPath = repoEntry . databasePath ( ) ;
}
// add sync db to internal map (use as index size + 1 because the local database has index 0)
m_syncDbs . emplace_back ( make_unique < AlpmDatabase > ( repoEntry . name ( ) , dbPath , RepositoryUsage : : None , repoEntry . sigLevel ( ) , m_syncDbs . size ( ) + 1 ) ) ;
syncDb = m_syncDbs . back ( ) . get ( ) ;
m_syncDbMap . emplace ( repoEntry . name ( ) , syncDb ) ;
syncDb - > setSourcesDirectory ( repoEntry . sourceDir ( ) ) ;
syncDb - > setPackagesDirectory ( repoEntry . packageDir ( ) ) ;
2016-02-15 18:26:05 +01:00
if ( ! repoEntry . maxDatabaseAge ( ) . isNull ( ) ) {
syncDb - > setMaxPackageAge ( repoEntry . maxDatabaseAge ( ) ) ;
}
2016-02-14 23:48:43 +01:00
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
cerr < < shchar < < " Added database [ " < < repoEntry . name ( ) < < ' ] ' < < endl ;
2015-08-19 02:13:28 +02:00
}
}
}
if ( syncDb ) {
2016-02-14 23:48:43 +01:00
syncDb - > serverUrls ( ) < < repoEntry . servers ( ) ;
2015-08-19 02:13:28 +02:00
}
2015-08-10 22:46:01 +02:00
}
2016-02-14 23:48:43 +01:00
2015-09-04 14:37:01 +02:00
// add upgrade sources
for ( const RepoEntry & repoEntry : m_config . repoEntries ( ) ) {
try {
2015-12-08 18:59:17 +01:00
auto & upgradeSources = m_syncDbMap . at ( repoEntry . name ( ) ) - > upgradeSources ( ) ;
2015-09-04 14:37:01 +02:00
for ( const auto & upgradeSourceName : repoEntry . upgradeSources ( ) ) {
if ( auto * source = repositoryByName ( upgradeSourceName ) ) {
upgradeSources < < source ;
} else {
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Warning: The specified upgrade source \" " < < upgradeSourceName < < " \" can not be found and will be ignored. " < < endl ;
2015-09-04 14:37:01 +02:00
}
}
} catch ( const out_of_range & ) {
// entry should have been added before
}
}
2015-08-10 22:46:01 +02:00
}
2015-09-05 17:25:05 +02:00
/*!
* \ brief Initiates all ALPM data bases .
2016-02-14 23:48:43 +01:00
* \ remarks Must be called , after all relevant sync databases have been added ( eg . via applyPacmanConfig ( ) ) .
2015-09-05 17:25:05 +02:00
*/
2015-09-11 21:59:47 +02:00
void Manager : : initAlpmDataBases ( bool computeRequiredBy )
2016-02-14 23:48:43 +01:00
{
2015-09-11 21:59:47 +02:00
{
2016-02-14 23:48:43 +01:00
// call the init method
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
cerr < < " Initializing ALPM databases ... " ;
cerr . flush ( ) ;
}
2015-09-11 21:59:47 +02:00
QList < PackageLoader * > loaders ;
2015-12-08 18:59:17 +01:00
loaders . reserve ( m_syncDbMap . size ( ) + 1 ) ;
2015-09-11 21:59:47 +02:00
loaders < < localDataBase ( ) - > init ( ) ;
2015-12-08 18:59:17 +01:00
for ( auto & syncDbEntry : m_syncDbMap ) {
2015-09-11 21:59:47 +02:00
loaders < < syncDbEntry . second - > init ( ) ;
}
for ( auto * loader : loaders ) {
2016-02-14 23:48:43 +01:00
if ( loader ) {
loader - > future ( ) . waitForFinished ( ) ;
delete loader ;
}
2015-09-11 21:59:47 +02:00
}
2016-02-14 23:48:43 +01:00
for ( auto & syncDbEntry : m_syncDbMap ) {
syncDbEntry . second - > updateGroups ( ) ;
}
}
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
cerr < < " DONE " < < endl ;
2015-09-11 21:59:47 +02:00
}
2016-02-14 23:48:43 +01:00
2015-09-11 21:59:47 +02:00
// compute required-by and optional-for
if ( computeRequiredBy ) {
2016-02-14 23:48:43 +01:00
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
cerr < < " Calculating required-by/optional-for ... " ;
cerr . flush ( ) ;
}
2015-09-11 21:59:47 +02:00
QList < QFuture < void > > futures ;
2015-12-08 18:59:17 +01:00
futures . reserve ( m_syncDbMap . size ( ) + 1 ) ;
2015-09-11 21:59:47 +02:00
futures < < localDataBase ( ) - > computeRequiredBy ( * this ) ;
2015-12-08 18:59:17 +01:00
for ( auto & syncDbEntry : m_syncDbMap ) {
2015-09-11 21:59:47 +02:00
futures < < syncDbEntry . second - > computeRequiredBy ( * this ) ;
}
for ( auto & future : futures ) {
future . waitForFinished ( ) ;
}
2016-02-14 23:48:43 +01:00
if ( m_config . isVerbose ( ) | | m_config . runServer ( ) ) {
cerr < < " DONE " < < endl ;
}
2015-09-11 21:59:47 +02:00
}
2016-02-14 23:48:43 +01:00
2015-09-11 21:59:47 +02:00
}
2016-01-18 20:34:29 +01:00
/*!
* \ brief Returns whether automatic cache maintenance is enabled .
* \ remarks If enabled , the cache will be cleaned and saved frequently .
*/
bool Manager : : isAutoCacheMaintenanceEnabled ( ) const
{
return m_cacheTimer & & m_cacheTimer - > isActive ( ) ;
}
/*!
* \ brief Sets whether automatic cache maintenacne is enabled .
* \ sa isAutoCacheMaintenanceEnabled ( )
*/
void Manager : : setAutoCacheMaintenanceEnabled ( bool enabled )
{
if ( isAutoCacheMaintenanceEnabled ( ) ! = enabled ) {
if ( enabled ) {
if ( ! m_cacheTimer ) {
m_cacheTimer = make_unique < QTimer > ( ) ;
m_cacheTimer - > setInterval ( 5 * 60 * 1000 ) ;
QObject : : connect ( m_cacheTimer . get ( ) , & QTimer : : timeout , bind ( & Manager : : maintainCache , this ) ) ;
}
m_cacheTimer - > start ( ) ;
} else {
m_cacheTimer - > stop ( ) ;
}
}
}
2015-09-11 21:59:47 +02:00
/*!
* \ brief Writes the cache for all repositories where caching makes sense .
*/
void Manager : : writeCache ( )
2015-09-05 17:25:05 +02:00
{
2015-09-11 21:59:47 +02:00
// could iterate through all repos and check isCachingUseful() but
// currently its just the AUR which is needed to be cached
if ( userRepository ( ) ) {
QFile file ( config ( ) . cacheDir ( ) % QChar ( ' / ' ) % userRepository ( ) - > name ( ) % QStringLiteral ( " .cache " ) ) ;
if ( file . open ( QFileDevice : : WriteOnly ) ) {
QDataStream stream ( & file ) ;
userRepository ( ) - > writeToCacheStream ( stream ) ;
// if warnings/errors occur, these will be printed directly by writeToCacheStream()
} else {
cerr < < shchar < < " Warning: Unable to write cache file for the AUR. " < < endl ;
}
2015-09-05 17:25:05 +02:00
}
2015-09-11 21:59:47 +02:00
}
void Manager : : restoreCache ( )
{
// could iterate through all repos and check isCachingUseful() but
// currently its just the AUR which is needed to be cached
if ( userRepository ( ) ) {
QFile file ( config ( ) . cacheDir ( ) % QChar ( ' / ' ) % userRepository ( ) - > name ( ) % QStringLiteral ( " .cache " ) ) ;
if ( file . exists ( ) ) {
if ( file . open ( QFileDevice : : ReadOnly ) ) {
QDataStream stream ( & file ) ;
userRepository ( ) - > restoreFromCacheStream ( stream ) ;
// if warnings/errors occur, these will be printed directly by restoreFromCacheStream()
} else {
cerr < < shchar < < " Warning: Unable to open cache file for the AUR. " < < endl ;
}
}
2015-09-05 17:25:05 +02:00
}
}
2016-01-18 20:34:29 +01:00
void Manager : : cleanCache ( )
{
// currently clear only AUR cache
if ( userRepository ( ) ) {
userRepository ( ) - > cleanOutdatedPackages ( ) ;
}
}
void Manager : : wipeCache ( )
{
// currently wipe only AUR cache
if ( userRepository ( ) ) {
userRepository ( ) - > wipePackages ( ) ;
}
}
void Manager : : maintainCache ( )
{
cleanCache ( ) ;
// TODO: write cache only when modified
writeCache ( ) ;
}
2015-08-10 22:46:01 +02:00
/*!
* \ brief Returns a list of all sync databases .
* \ remarks Sync databases must be registered with parsePacmanConfig ( ) before .
*/
2015-12-08 18:59:17 +01:00
const std : : map < QString , AlpmDatabase * > & Manager : : syncDatabases ( ) const
2015-08-10 22:46:01 +02:00
{
2015-12-08 18:59:17 +01:00
return m_syncDbMap ; // m_syncDbs has been filled when the databases were registered
2015-08-10 22:46:01 +02:00
}
/*!
* \ brief Returns basic information about all repositories known to the manager .
*
* The results include the local database ( " local " ) and the names of
* the registered sync databases .
*/
2015-09-21 22:16:19 +02:00
const QJsonObject & Manager : : basicRepoInfo ( ) const
2015-08-10 22:46:01 +02:00
{
if ( m_basicRepoInfo . isEmpty ( ) ) {
2015-08-19 02:13:28 +02:00
QMutexLocker locker ( & m_basicRepoInfoMutex ) ;
if ( m_basicRepoInfo . isEmpty ( ) ) {
2015-09-04 14:37:01 +02:00
// add local data base
2015-11-03 18:19:24 +01:00
{
QReadLocker locker ( localDataBase ( ) - > lock ( ) ) ;
m_basicRepoInfo . insert ( localDataBase ( ) - > name ( ) , localDataBase ( ) - > basicInfo ( ) ) ;
}
2015-09-04 14:37:01 +02:00
// add sync data bases
2015-09-05 17:25:05 +02:00
for ( const auto & syncDb : syncDatabases ( ) ) {
2015-08-19 02:13:28 +02:00
// check if the "sync" database is actually used for syncing
2015-11-03 18:19:24 +01:00
QReadLocker locker ( syncDb . second - > lock ( ) ) ;
2015-09-04 14:37:01 +02:00
auto usage = syncDb . second - > usage ( ) ;
2016-02-14 23:48:43 +01:00
if ( ( usage & RepositoryUsage : : Sync ) | | ( usage & RepositoryUsage : : Install ) | | ( usage & RepositoryUsage : : Upgrade ) ) {
2015-09-21 22:16:19 +02:00
m_basicRepoInfo . insert ( syncDb . first , syncDb . second - > basicInfo ( ) ) ;
2015-08-19 02:13:28 +02:00
} else {
2015-09-21 22:16:19 +02:00
m_basicRepoInfo . insert ( syncDb . first , syncDb . second - > basicInfo ( ) ) ;
2015-08-19 02:13:28 +02:00
}
2015-08-10 22:46:01 +02:00
}
2015-09-04 14:37:01 +02:00
// add AUR
2015-09-21 22:16:19 +02:00
if ( userRepository ( ) ) {
2015-11-03 18:19:24 +01:00
QReadLocker locker ( userRepository ( ) - > lock ( ) ) ;
2015-09-21 22:16:19 +02:00
m_basicRepoInfo . insert ( userRepository ( ) - > name ( ) , userRepository ( ) - > basicInfo ( ) ) ;
2015-09-04 14:37:01 +02:00
}
2015-08-10 22:46:01 +02:00
}
}
return m_basicRepoInfo ;
}
/*!
* \ brief Returns package information for the specified selection of packages .
2015-09-27 19:29:45 +02:00
* \ remarks Does not request any information and hence will only return information
* which does not need to be requested or has been requested yet .
2015-08-10 22:46:01 +02:00
*/
2015-09-21 22:16:19 +02:00
const QJsonArray Manager : : packageInfo ( const QJsonObject & pkgSelection , PackageInfoPart part ) const
2015-08-10 22:46:01 +02:00
{
2015-09-21 22:16:19 +02:00
QJsonArray results ;
2015-09-04 14:37:01 +02:00
for ( auto i = pkgSelection . constBegin ( ) , end = pkgSelection . constEnd ( ) ; i ! = end ; + + i ) {
if ( auto * repo = repositoryByName ( i . key ( ) ) ) {
for ( const auto & entry : i . value ( ) . toArray ( ) ) {
const auto entryObj = entry . toObject ( ) ;
const auto pkgName = entryObj . value ( QStringLiteral ( " name " ) ) . toString ( ) ;
if ( ! pkgName . isEmpty ( ) ) {
2015-09-21 22:16:19 +02:00
QJsonObject res ;
2015-09-29 21:52:30 +02:00
res . insert ( QStringLiteral ( " name " ) , pkgName ) ;
res . insert ( QStringLiteral ( " repo " ) , repo - > name ( ) ) ;
const auto index = entryObj . value ( QStringLiteral ( " index " ) ) ;
if ( ! index . isNull ( ) & & ! index . isUndefined ( ) ) {
res . insert ( QStringLiteral ( " index " ) , index ) ;
}
2015-09-04 14:37:01 +02:00
if ( auto * pkg = repo - > packageByName ( pkgName ) ) {
2015-09-21 22:16:19 +02:00
if ( part & Basics ) {
res . insert ( QStringLiteral ( " basics " ) , pkg - > basicInfo ( ) ) ;
}
if ( part & Details ) {
res . insert ( QStringLiteral ( " details " ) , pkg - > detailedInfo ( ) ) ;
}
2015-09-04 14:37:01 +02:00
} else {
2015-09-21 22:16:19 +02:00
res . insert ( QStringLiteral ( " error " ) , QStringLiteral ( " na " ) ) ;
2015-09-04 14:37:01 +02:00
}
2015-09-21 22:16:19 +02:00
results < < res ;
2015-09-04 14:37:01 +02:00
}
2015-08-10 22:46:01 +02:00
}
2015-09-04 14:37:01 +02:00
} else {
// specified repository can not be found
QJsonObject errorObj ;
errorObj . insert ( QStringLiteral ( " repo " ) , i . key ( ) ) ;
errorObj . insert ( QStringLiteral ( " error " ) , QStringLiteral ( " na " ) ) ;
2015-09-21 22:16:19 +02:00
results < < errorObj ;
2015-08-10 22:46:01 +02:00
}
2015-09-04 14:37:01 +02:00
2015-08-10 22:46:01 +02:00
}
2015-09-21 22:16:19 +02:00
return results ;
2015-08-10 22:46:01 +02:00
}
/*!
* \ brief Returns group information for the local database and all registred sync databases .
*/
const QJsonArray & Manager : : groupInfo ( ) const
{
if ( m_groupInfo . empty ( ) ) {
2015-08-19 02:13:28 +02:00
QMutexLocker locker ( & m_groupInfoMutex ) ;
if ( m_groupInfo . empty ( ) ) {
2015-09-11 21:59:47 +02:00
m_groupInfo < < localDataBase ( ) - > groupInfo ( ) ;
2015-12-08 18:59:17 +01:00
for ( const auto & db : m_syncDbMap ) {
2015-09-04 14:37:01 +02:00
m_groupInfo < < db . second - > groupInfo ( ) ;
2015-08-19 02:13:28 +02:00
}
2015-08-10 22:46:01 +02:00
}
}
return m_groupInfo ;
}
2015-09-21 22:16:19 +02:00
/*!
2016-02-15 18:26:05 +01:00
* \ brief Add the local database .
2015-09-21 22:16:19 +02:00
*/
2016-02-14 23:48:43 +01:00
void Manager : : addLocalDatabase ( )
2015-09-21 22:16:19 +02:00
{
2016-02-14 23:48:43 +01:00
m_localDb = make_unique < AlpmDatabase > ( QStringLiteral ( " local " ) , config ( ) . alpmDbPath ( ) % QStringLiteral ( " /local " ) , RepositoryUsage : : None , SignatureLevel : : UseDefault , 0 ) ;
2015-09-21 22:16:19 +02:00
}
/*!
2016-02-14 23:48:43 +01:00
* \ brief Removes all ALPM databases .
2015-09-21 22:16:19 +02:00
*/
2016-02-14 23:48:43 +01:00
void Manager : : removeAllDatabases ( )
2015-09-21 22:16:19 +02:00
{
2016-02-14 23:48:43 +01:00
m_localDb . reset ( ) ;
m_syncDbs . clear ( ) ;
m_syncDbMap . clear ( ) ;
2015-09-21 22:16:19 +02:00
}
2015-08-10 22:46:01 +02:00
/*!
* \ brief Returns the ALPM database with the specified name .
*/
2015-09-05 17:25:05 +02:00
const AlpmDatabase * Manager : : databaseByName ( const QString & dbName ) const
2015-08-10 22:46:01 +02:00
{
2015-09-04 14:37:01 +02:00
if ( dbName . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-11 21:59:47 +02:00
return localDataBase ( ) ;
2015-08-10 22:46:01 +02:00
} else {
2015-09-04 14:37:01 +02:00
try {
2015-12-08 18:59:17 +01:00
return m_syncDbMap . at ( dbName ) ;
2015-09-04 14:37:01 +02:00
} catch ( const out_of_range & ) {
return nullptr ;
}
2015-08-10 22:46:01 +02:00
}
}
/*!
* \ brief Returns the ALPM database with the specified name .
*/
2015-09-05 17:25:05 +02:00
AlpmDatabase * Manager : : databaseByName ( const QString & dbName )
2015-08-10 22:46:01 +02:00
{
2015-09-04 14:37:01 +02:00
if ( dbName . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-11 21:59:47 +02:00
return localDataBase ( ) ;
2015-08-10 22:46:01 +02:00
} else {
2015-09-04 14:37:01 +02:00
try {
2015-12-08 18:59:17 +01:00
return m_syncDbMap . at ( dbName ) ;
2015-09-04 14:37:01 +02:00
} catch ( const out_of_range & ) {
return nullptr ;
}
2015-08-10 22:46:01 +02:00
}
}
/*!
2015-09-04 14:37:01 +02:00
* \ brief Returns the package source with the specified name .
2015-08-10 22:46:01 +02:00
*/
2015-09-04 14:37:01 +02:00
const Repository * Manager : : repositoryByName ( const QString & name ) const
2015-08-10 22:46:01 +02:00
{
2015-09-04 14:37:01 +02:00
if ( name . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-11 21:59:47 +02:00
return localDataBase ( ) ;
2015-09-04 14:37:01 +02:00
} else if ( config ( ) . isAurEnabled ( ) & & ( name . compare ( QLatin1String ( " aur " ) , Qt : : CaseInsensitive ) = = 0 ) ) {
return userRepository ( ) ;
} else {
try {
2015-12-08 18:59:17 +01:00
return m_syncDbMap . at ( name ) ;
2015-09-04 14:37:01 +02:00
} catch ( const out_of_range & ) {
return nullptr ;
}
}
2015-08-10 22:46:01 +02:00
}
/*!
2015-09-04 14:37:01 +02:00
* \ brief Returns the package source with the specified name .
2015-08-10 22:46:01 +02:00
*/
2015-09-04 14:37:01 +02:00
Repository * Manager : : repositoryByName ( const QString & name )
2015-08-10 22:46:01 +02:00
{
2015-09-04 14:37:01 +02:00
if ( name . compare ( QLatin1String ( " local " ) , Qt : : CaseInsensitive ) = = 0 ) {
2015-09-11 21:59:47 +02:00
return localDataBase ( ) ;
2015-09-04 14:37:01 +02:00
} else if ( config ( ) . isAurEnabled ( ) & & ( name . compare ( QLatin1String ( " aur " ) , Qt : : CaseInsensitive ) = = 0 ) ) {
return userRepository ( ) ;
} else {
2015-08-10 22:46:01 +02:00
try {
2015-12-08 18:59:17 +01:00
return m_syncDbMap . at ( name ) ;
2015-09-04 14:37:01 +02:00
} catch ( const out_of_range & ) {
return nullptr ;
2015-08-10 22:46:01 +02:00
}
}
2015-09-04 14:37:01 +02:00
}
/*!
2016-02-15 18:26:05 +01:00
* \ brief Finds the default path for the database with the specified \ a name .
* \ remarks
* - If the database couldn ' t be located and \ a printError is true
* an error message is printed to cerr .
* - If \ a updatesRequired is false using the pacman sync dbs is not considered .
* - This is used if the database path hasn ' t been specified explicitely .
2015-09-04 14:37:01 +02:00
*/
2016-02-15 18:26:05 +01:00
QString Manager : : findDatabasePath ( const QString & name , bool updatesRequired , bool printError ) const
{
QFileInfo dbPathRegular ( m_config . storageDir ( ) % QStringLiteral ( " /sync/ " ) % name % QStringLiteral ( " .db " ) ) ;
QFileInfo dbPathWithFiles ( m_config . storageDir ( ) % QStringLiteral ( " /sync/ " ) % name % QStringLiteral ( " .files " ) ) ;
if ( dbPathWithFiles . isFile ( ) & & ( ! dbPathRegular . isFile ( ) | | dbPathWithFiles . lastModified ( ) > dbPathRegular . lastModified ( ) ) ) {
2016-02-18 17:11:37 +01:00
return dbPathWithFiles . absoluteFilePath ( ) ;
2016-02-15 18:26:05 +01:00
} else if ( dbPathRegular . isFile ( ) ) {
2016-02-18 17:11:37 +01:00
return dbPathRegular . absoluteFilePath ( ) ;
2016-02-15 18:26:05 +01:00
} else if ( ! updatesRequired ) {
// can't find database file in storage directory and database should not be updated automatically
// -> it might be possible to use the databases from pacman
QFileInfo pacmanDbPathRegular ( m_config . alpmDbPath ( ) % QStringLiteral ( " /sync/ " ) % name % QStringLiteral ( " .db " ) ) ;
QFileInfo pacmanDbPathWithFiles ( m_config . alpmDbPath ( ) % QStringLiteral ( " /sync/ " ) % name % QStringLiteral ( " .files " ) ) ;
if ( pacmanDbPathWithFiles . isFile ( ) & & ( ! pacmanDbPathRegular . isFile ( ) | | pacmanDbPathWithFiles . lastModified ( ) > pacmanDbPathRegular . lastModified ( ) ) ) {
2016-02-18 17:11:37 +01:00
return pacmanDbPathWithFiles . absoluteFilePath ( ) ;
2016-02-15 18:26:05 +01:00
} else if ( pacmanDbPathRegular . isFile ( ) ) {
2016-02-18 17:11:37 +01:00
return pacmanDbPathRegular . absoluteFilePath ( ) ;
2016-02-15 18:26:05 +01:00
}
}
if ( printError ) {
cerr < < shchar < < " Error: Unable to locate database file for [ " < < name . toLocal8Bit ( ) . data ( ) < < " ] " < < endl ;
}
}
/*!
* \ brief Returns a database path for the database with the specified \ a name .
*/
QString Manager : : proposedDatabasePath ( const QString & name , bool files ) const
2015-09-04 14:37:01 +02:00
{
2016-02-15 18:26:05 +01:00
return m_config . storageDir ( ) % QStringLiteral ( " /sync/ " ) % name % ( files ? QStringLiteral ( " .files " ) : QStringLiteral ( " .db " ) ) ;
2015-08-10 22:46:01 +02:00
}
}