libzypp 17.38.1
econfdict.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
11#include "econfdict.h"
12
13#include <tuple> // std::ignore
14#include <optional>
15
16#include <zypp-core/Pathname.h>
19
20namespace zypp::parser {
21
22 namespace econf {
23
36 {
38
40 : ConfigurationContext( "/etc", "/usr/etc" )
41 {}
42
43 ConfigurationContext( std::optional<Pathname> etcDir_r, std::optional<Pathname> usrDir_r )
44 : _etcDir( std::move(etcDir_r ) )
45 , _usrDir( std::move(usrDir_r ) )
46 {}
47
48 const std::optional<Pathname> & etcDir() const { return _etcDir; }
49 const std::optional<Pathname> & usrDir() const { return _usrDir; }
50
51 std::vector<Pathname> getConfigFiles( const std::string & stem_r, const Pathname & root_r = Pathname("/") ) const
52 {
53 // configStem must denote a config file below some root dir:
54 // [PROJECT/]EXAMPLE[.SUFFIX]
55 Pathname configStem { stem_r };
56 if ( configStem.relative() ) {
57 if ( configStem.relativeDotDot() )
58 ZYPP_THROW( Exception(str::sprint("Config stem must not refer to '../':", configStem)) );
59 configStem = configStem.absolutename();
60 }
61 if ( configStem.emptyOrRoot() )
62 ZYPP_THROW( Exception(str::sprint("Config stem must not be empty:", configStem)) );
63 pMIL( "getConfigFiles for stem", configStem, "below", root_r, "in", _etcDir, _usrDir );
64 Pathname configDir { configStem.extend( ".d" ) }; // [PROJECT/]EXAMPLE[.SUFFIX].d
65 std::string configSuffix { configStem.extension() }; // [.SUFFIX]
66
67 // relevant lookup dirs in order of preference:
68 std::vector<Pathname> lookupDirs;
69 if ( _etcDir )
70 takeLookupDirIf( lookupDirs, root_r / *_etcDir ); // system configuration
71 takeLookupDirIf( lookupDirs, root_r / "/run" ); // /run for ephemeral overrides
72 if ( _usrDir )
73 takeLookupDirIf( lookupDirs, root_r / *_usrDir ); // vendor configuration
74
75 // now collect base config and drop-ins to parse:
76 PathInfo basecfgToParse; // the full (base) config to parse (if any)
77 std::map<std::string,PathInfo> dropinsToParse; // drop-ins to parse (1st. wins; lex sorted)
78
79 for ( const Pathname & ldir : lookupDirs ) {
80 // base config
81 PathInfo basecfg { ldir / configStem };
82 takeOrMask( basecfg, basecfgToParse );
83
84 // dropins
85 PathInfo dropinDir { ldir / configDir };
86 if ( dropinDir.isDir() ) {
87 filesystem::dirForEachExt( dropinDir.path(), [&]( const zypp::Pathname &p, const zypp::filesystem::DirEntry &entry ) {
88 if ( entry.name[0] == '.' )
89 return true;
90 if ( not ( configSuffix.empty() || str::hasSuffix( entry.name, configSuffix ) ) )
91 return true;
92 PathInfo dropin { p / entry.name };
93 takeOrMask( dropin, dropinsToParse[entry.name] );
94 return true;
95 } );
96 }
97 }
98
99 // prepare the list to parse
100 std::vector<Pathname> ret;
101 handOutIf( ret, basecfgToParse );
102 for ( const auto & [_,p] : dropinsToParse ) {
103 std::ignore = _; // silence warning: unused variable
104 handOutIf( ret, p );
105 }
106 if ( ret.empty() )
107 pMIL( "No config files found for stem", configStem, "below", root_r );
108 return ret;
109 }
110
111 private:
113 static void takeLookupDirIf( std::vector<Pathname> & lookupDirs_r, Pathname dir_r )
114 {
115 if ( PathInfo(dir_r).isDir() )
116 lookupDirs_r.push_back( dir_r );
117 }
118
120 static bool isSet( const PathInfo & file_r )
121 { return not file_r.path().empty(); }
122
124 static void takeOrMask( const PathInfo & file_r, PathInfo & toParse_r )
125 {
126 if ( file_r.isExist() && not file_r.isDir() ) {
127 if ( isSet( toParse_r ) ) {
128 pDBG( "masked", file_r, "by", toParse_r );
129 } else {
130 toParse_r = std::move(file_r); //file_r.path();
131 }
132 }
133 }
134
136 static void handOutIf( std::vector<Pathname> & ret_r, const PathInfo & file_r )
137 {
138 if ( isSet( file_r ) ) {
139 pMIL( "take", file_r );
140 ret_r.push_back( file_r.path() );
141 }
142 }
143
144 private:
145 std::optional<Pathname> _etcDir;
146 std::optional<Pathname> _usrDir;
147 };
148
149 } // namespace econf
150
153
154 EconfDict::EconfDict( const std::string & stem_r, const Pathname & root_r )
155 : IniDict()
156 {
157 for ( const Pathname & file : econf::ConfigurationContext().getConfigFiles( stem_r, root_r ) ) {
158 read( file );
159 }
160 pDBG( stem_r, "below", root_r, ":", *this );
161 }
162} // namespace zypp::parser
163
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define pMIL
Definition LogTools.h:305
#define pDBG
Definition LogTools.h:304
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition Pathname.h:182
bool relativeDotDot() const
Test for a relative path referring to ../.
Definition Pathname.h:124
bool emptyOrRoot() const
Test for "" or "/".
Definition Pathname.h:127
bool empty() const
Test for an empty path.
Definition Pathname.h:117
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition Pathname.h:148
std::string extension() const
Return all of the characters in name after and including the last dot in the last element of name.
Definition Pathname.h:144
bool relative() const
Test for a relative path.
Definition Pathname.h:121
void read(const InputStream &is, const ProgressData::ReceiverFnc &progress=ProgressData::ReceiverFnc())
Fill a dictionary from a InputStream containing a ini structured file.
Definition inidict.cc:50
IniDict(const InputStream &is, const ProgressData::ReceiverFnc &progress=ProgressData::ReceiverFnc())
Creates a dictionary from a InputStream containing a ini structured file.
Definition inidict.cc:40
Definition ansi.h:855
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition PathInfo.cc:598
std::string sprint(Args &&... args)
Print words as string.
Definition LogTools.h:266
Listentry returned by readdir.
Definition PathInfo.h:509
Provide access to the prioritized list of files and drop-ins to read and merge for a specific config ...
Definition econfdict.cc:36
static void takeOrMask(const PathInfo &file_r, PathInfo &toParse_r)
The 1st viable file_r is stored in toParse_r; candidates found later are masked.
Definition econfdict.cc:124
std::vector< Pathname > getConfigFiles(const std::string &stem_r, const Pathname &root_r=Pathname("/")) const
Definition econfdict.cc:51
static void handOutIf(std::vector< Pathname > &ret_r, const PathInfo &file_r)
Store set values in ret_r.
Definition econfdict.cc:136
static void takeLookupDirIf(std::vector< Pathname > &lookupDirs_r, Pathname dir_r)
Remember valid lookup dirs.
Definition econfdict.cc:113
std::optional< Pathname > _etcDir
system configuration: /etc
Definition econfdict.cc:145
const std::optional< Pathname > & usrDir() const
Definition econfdict.cc:49
static bool isSet(const PathInfo &file_r)
An empty path denotes the unset value.
Definition econfdict.cc:120
ConfigurationContext(std::optional< Pathname > etcDir_r, std::optional< Pathname > usrDir_r)
Definition econfdict.cc:43
const std::optional< Pathname > & etcDir() const
Definition econfdict.cc:48
std::optional< Pathname > _usrDir
vendor configuration: distconfdir (/usr/etc)
Definition econfdict.cc:146