#include "zypp/base/InputStream.h"
#include "zypp/base/LogTools.h"
#include "zypp/base/Gettext.h"
+#include "zypp/base/DefaultIntegral.h"
#include "zypp/base/Function.h"
#include "zypp/base/Regex.h"
#include "zypp/PathInfo.h"
/**
* \short Simple callback to collect the results
*
- * Classes like RepoFileParser call the callback
+ * Classes like RepoFileReader call the callback
* once per each repo in a file.
*
* Passing this functor as callback, you can collect
MIL << "repo file: " << file << endl;
RepoCollector collector;
parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) );
- return collector.repos;
+ return std::move(collector.repos);
}
////////////////////////////////////////////////////////////////////////////
{
MIL << "directory " << dir << endl;
std::list<RepoInfo> repos;
- std::list<Pathname> entries;
- if ( filesystem::readdir( entries, dir, false ) != 0 )
+ bool nonroot( geteuid() != 0 );
+ if ( nonroot && ! PathInfo(dir).userMayRX() )
{
- // TranslatorExplanation '%s' is a pathname
- ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str())));
+ JobReport::warning( formatNAC(_("Cannot read repo directory '%1%': Permission denied")) % dir );
}
-
- str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
- for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
+ else
{
- if (str::regex_match(it->extension(), allowedRepoExt))
+ std::list<Pathname> entries;
+ if ( filesystem::readdir( entries, dir, false ) != 0 )
{
- std::list<RepoInfo> tmp = repositories_in_file( *it );
- repos.insert( repos.end(), tmp.begin(), tmp.end() );
+ // TranslatorExplanation '%s' is a pathname
+ ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str())));
+ }
- //std::copy( collector.repos.begin(), collector.repos.end(), std::back_inserter(repos));
- //MIL << "ok" << endl;
+ str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
+ for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
+ {
+ if ( str::regex_match(it->extension(), allowedRepoExt) )
+ {
+ if ( nonroot && ! PathInfo(*it).userMayR() )
+ {
+ JobReport::warning( formatNAC(_("Cannot read repo file '%1%': Permission denied")) % *it );
+ }
+ else
+ {
+ const std::list<RepoInfo> & tmp( repositories_in_file( *it ) );
+ repos.insert( repos.end(), tmp.begin(), tmp.end() );
+ }
+ }
}
}
return repos;
init_knownRepositories();
}
+ ~Impl()
+ {
+ // trigger appdata refresh if some repos change
+ if ( _reposDirty && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
+ {
+ try {
+ std::list<Pathname> entries;
+ filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
+ if ( ! entries.empty() )
+ {
+ ExternalProgram::Arguments cmd;
+ cmd.push_back( "<" ); // discard stdin
+ cmd.push_back( ">" ); // discard stdout
+ cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
+ for ( const auto & rinfo : repos() )
+ {
+ if ( ! rinfo.enabled() )
+ continue;
+ cmd.push_back( "-R" );
+ cmd.push_back( rinfo.alias() );
+ cmd.push_back( "-t" );
+ cmd.push_back( rinfo.type().asString() );
+ cmd.push_back( "-p" );
+ cmd.push_back( rinfo.metadataPath().asString() );
+ }
+
+ for_( it, entries.begin(), entries.end() )
+ {
+ PathInfo pi( *it );
+ //DBG << "/tmp/xx ->" << pi << endl;
+ if ( pi.isFile() && pi.userMayRX() )
+ {
+ // trigger plugin
+ cmd[2] = pi.asString(); // [2] - PROGRAM
+ ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
+ }
+ }
+ }
+ }
+ catch (...) {} // no throw in dtor
+ }
+ }
+
public:
- bool repoEmpty() const { return _repos.empty(); }
- RepoSizeType repoSize() const { return _repos.size(); }
- RepoConstIterator repoBegin() const { return _repos.begin(); }
- RepoConstIterator repoEnd() const { return _repos.end(); }
+ bool repoEmpty() const { return repos().empty(); }
+ RepoSizeType repoSize() const { return repos().size(); }
+ RepoConstIterator repoBegin() const { return repos().begin(); }
+ RepoConstIterator repoEnd() const { return repos().end(); }
bool hasRepo( const std::string & alias ) const
- { return foundAliasIn( alias, _repos ); }
+ { return foundAliasIn( alias, repos() ); }
RepoInfo getRepo( const std::string & alias ) const
{
- RepoConstIterator it( findAlias( alias, _repos ) );
- return it == _repos.end() ? RepoInfo::noRepo : *it;
+ RepoConstIterator it( findAlias( alias, repos() ) );
+ return it == repos().end() ? RepoInfo::noRepo : *it;
}
public:
void getRepositoriesInService( const std::string & alias, OutputIterator out ) const
{
MatchServiceAlias filter( alias );
- std::copy( boost::make_filter_iterator( filter, _repos.begin(), _repos.end() ),
- boost::make_filter_iterator( filter, _repos.end(), _repos.end() ),
+ std::copy( boost::make_filter_iterator( filter, repos().begin(), repos().end() ),
+ boost::make_filter_iterator( filter, repos().end(), repos().end() ),
out);
}
void init_knownServices();
void init_knownRepositories();
+ const RepoSet & repos() const { return _reposX; }
+ RepoSet & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; }
+
private:
RepoManagerOptions _options;
- RepoSet _repos;
+ RepoSet _reposX;
ServiceSet _services;
+ DefaultIntegral<bool,false> _reposDirty;
+
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
/** clone for RWCOW_pointer */
// set the downloaded packages path for the repo
repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) );
// remember it
- _repos.insert( repoInfo );
+ _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
// detect orphaned repos belonging to a deleted service
const std::string & serviceAlias( repoInfo.service() );
"Valid metadata not found at specified URLs",
info.baseUrlsSize() ) );
+ // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
+ media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 );
+
// try urls one by one
for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
{
// ok we have the metadata, now exchange
// the contents
filesystem::exchange( tmpdir.path(), mediarootpath );
+ reposManip(); // remember to trigger appdata refresh
// we are done.
return;
MIL << "Try adding repo " << info << endl;
RepoInfo tosave = info;
- if ( _repos.find(tosave) != _repos.end() )
+ if ( repos().find(tosave) != repos().end() )
ZYPP_THROW(RepoAlreadyExistsException(info));
// check the first url for now
oinfo.setMetadataPath( metadataPath( tosave ) );
oinfo.setPackagesPath( packagesPath( tosave ) );
}
- _repos.insert(tosave);
+ reposManip().insert(tosave);
progress.set(90);
MIL << "Saving " << (*it).alias() << endl;
it->setFilepath(repofile.asString());
it->dumpAsIniOn(file);
- _repos.insert(*it);
+ reposManip().insert(*it);
HistoryLog(_options.rootDir).addRepository(*it);
}
// TranslatorExplanation '%s' is a filename
ZYPP_THROW(RepoException( todelete, str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
}
- MIL << todelete.alias() << " sucessfully deleted." << endl;
+ MIL << todelete.alias() << " successfully deleted." << endl;
}
else
{
// now delete metadata (#301037)
cleanMetadata( todelete, mSubprogrcv );
cleanPackages( todelete, pSubprogrcv );
- _repos.erase(todelete);
- MIL << todelete.alias() << " sucessfully deleted." << endl;
+ reposManip().erase(todelete);
+ MIL << todelete.alias() << " successfully deleted." << endl;
HistoryLog(_options.rootDir).removeRepository(todelete);
return;
} // else filepath is empty
}
newinfo.setFilepath(toedit.filepath());
- _repos.erase(toedit);
- _repos.insert(newinfo);
+ reposManip().erase(toedit);
+ reposManip().insert(newinfo);
HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
MIL << "repo " << alias << " modified" << endl;
}
RepoInfo RepoManager::Impl::getRepositoryInfo( const std::string & alias, const ProgressData::ReceiverFnc & progressrcv )
{
- RepoConstIterator it( findAlias( alias, _repos ) );
- if ( it != _repos.end() )
+ RepoConstIterator it( findAlias( alias, repos() ) );
+ if ( it != repos().end() )
return *it;
RepoInfo info;
info.setAlias( alias );
// TranslatorExplanation '%s' is a filename
ZYPP_THROW(ServiceException( service, str::form( _("Can't delete '%s'"), location.c_str() ) ));
}
- MIL << alias << " sucessfully deleted." << endl;
+ MIL << alias << " successfully deleted." << endl;
}
else
{
it->dumpAsIniOn(file);
}
- MIL << alias << " sucessfully deleted from file " << location << endl;
+ MIL << alias << " successfully deleted from file " << location << endl;
}
// now remove all repositories added by this service
// if the repo url was not set by the repoindex parser, set service's url
Url url;
if ( it->baseUrlsEmpty() )
- url = service.url();
+ url = service.rawUrl();
else
{
// service repo can contain only one URL now, so no need to iterate.
- url = *it->baseUrlsBegin();
+ url = it->rawUrl(); // raw!
}
// libzypp currently has problem with separate url + path handling
// all other attributes follow the service request:
+ // changed name (raw!)
+ if ( oldRepo->rawName() != it->rawName() )
+ {
+ DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
+ oldRepo->setName( it->rawName() );
+ oldRepoModified = true;
+ }
+
// changed autorefresh
if ( oldRepo->autorefresh() != it->autorefresh() )
{
// changed url?
// service repo can contain only one URL now, so no need to iterate.
- if ( oldRepo->url() != it->url() )
+ if ( oldRepo->rawUrl() != it->rawUrl() )
{
- DBG << "Service repo " << it->alias() << " gets new URL " << it->url() << endl;
- oldRepo->setBaseUrl( it->url() );
+ DBG << "Service repo " << it->alias() << " gets new URL " << it->rawUrl() << endl;
+ oldRepo->setBaseUrl( it->rawUrl() );
oldRepoModified = true;
}