libzypp  17.38.7
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/APIConfig.h>
17 #include <zypp-core/Pathname.h>
18 #include <zypp-core/fs/PathInfo.h>
20 
21 namespace zypp::parser {
22 
23  namespace econf {
24 
37  {
40 
43  {}
44 
45  ConfigurationContext( std::optional<Pathname> etcDir_r, std::optional<Pathname> usrDir_r )
46  : _etcDir( std::move(etcDir_r) )
47  , _usrDir( std::move(usrDir_r) )
48  {}
49 
50  const std::optional<Pathname> & etcDir() const { return _etcDir; }
51  const std::optional<Pathname> & usrDir() const { return _usrDir; }
52 
53  std::vector<Pathname> getConfigFiles( const std::string & stem_r, const Pathname & root_r = Pathname("/") ) const
54  {
55  // configStem must denote a config file below some root dir:
56  // [PROJECT/]EXAMPLE[.SUFFIX]
57  Pathname configStem { stem_r };
58  if ( configStem.relative() ) {
59  if ( configStem.relativeDotDot() )
60  ZYPP_THROW( Exception(str::sprint("Config stem must not refer to '../':", configStem)) );
61  configStem = configStem.absolutename();
62  }
63  if ( configStem.emptyOrRoot() )
64  ZYPP_THROW( Exception(str::sprint("Config stem must not be empty:", configStem)) );
65  pMIL( "getConfigFiles for stem", configStem, "below", root_r, "in", _etcDir, _usrDir );
66  Pathname configDir { configStem.extend( ".d" ) }; // [PROJECT/]EXAMPLE[.SUFFIX].d
67  std::string configSuffix { configStem.extension() }; // [.SUFFIX]
68 
69  // relevant lookup dirs in order of preference:
70  std::vector<Pathname> lookupDirs;
71  if ( _etcDir )
72  takeLookupDirIf( lookupDirs, root_r / *_etcDir ); // system configuration
73  takeLookupDirIf( lookupDirs, root_r / "/run" ); // /run for ephemeral overrides
74  if ( _usrDir )
75  takeLookupDirIf( lookupDirs, root_r / *_usrDir ); // vendor configuration
76 
77  // now collect base config and drop-ins to parse:
78  PathInfo basecfgToParse; // the full (base) config to parse (if any)
79  std::map<std::string,PathInfo> dropinsToParse; // drop-ins to parse (1st. wins; lex sorted)
80 
81  for ( const Pathname & ldir : lookupDirs ) {
82  // base config
83  PathInfo basecfg { ldir / configStem };
84  takeOrMask( basecfg, basecfgToParse );
85 
86  // dropins
87  PathInfo dropinDir { ldir / configDir };
88  if ( dropinDir.isDir() ) {
89  filesystem::dirForEachExt( dropinDir.path(), [&]( const zypp::Pathname &p, const zypp::filesystem::DirEntry &entry ) {
90  if ( entry.name[0] == '.' )
91  return true;
92  if ( not ( configSuffix.empty() || str::hasSuffix( entry.name, configSuffix ) ) )
93  return true;
94  PathInfo dropin { p / entry.name };
95  takeOrMask( dropin, dropinsToParse[entry.name] );
96  return true;
97  } );
98  }
99  }
100 
101  // prepare the list to parse
102  std::vector<Pathname> ret;
103  handOutIf( ret, basecfgToParse );
104  for ( const auto & [_,p] : dropinsToParse ) {
105  std::ignore = _; // silence warning: unused variable
106  handOutIf( ret, p );
107  }
108  if ( ret.empty() )
109  pMIL( "No config files found for stem", configStem, "below", root_r );
110  return ret;
111  }
112 
113  private:
115  static void takeLookupDirIf( std::vector<Pathname> & lookupDirs_r, Pathname dir_r )
116  {
117  if ( PathInfo(dir_r).isDir() )
118  lookupDirs_r.push_back( dir_r );
119  }
120 
122  static bool isSet( const PathInfo & file_r )
123  { return not file_r.path().empty(); }
124 
126  static void takeOrMask( const PathInfo & file_r, PathInfo & toParse_r )
127  {
128  if ( file_r.isExist() && not file_r.isDir() ) {
129  if ( isSet( toParse_r ) ) {
130  pDBG( "masked", file_r, "by", toParse_r );
131  } else {
132  toParse_r = std::move(file_r); //file_r.path();
133  }
134  }
135  }
136 
138  static void handOutIf( std::vector<Pathname> & ret_r, const PathInfo & file_r )
139  {
140  if ( isSet( file_r ) ) {
141  pMIL( "take", file_r );
142  ret_r.push_back( file_r.path() );
143  }
144  }
145 
146 
147  private:
148  std::optional<Pathname> _etcDir;
149  std::optional<Pathname> _usrDir;
150  };
151 
152  Pathname ConfigurationContext::_defaultDistconfDir { APIConfig(LIBZYPP_ZYPPCONFDIR) };
153 
154  } // namespace econf
155 
157  {}
158 
159  EconfDict::EconfDict( const std::string & stem_r, const Pathname & root_r )
160  : IniDict()
161  {
162  for ( const Pathname & file : econf::ConfigurationContext().getConfigFiles( stem_r, root_r ) ) {
163  read( file );
164  }
165  pDBG( stem_r, "below", root_r, ":", *this );
166  }
167 
170 
172  { econf::ConfigurationContext::_defaultDistconfDir = std::move(path_r); }
173 } // namespace zypp::parser
174 
Listentry returned by readdir.
Definition: PathInfo.h:517
Thrown by EconfDict.
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:251
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
static void takeLookupDirIf(std::vector< Pathname > &lookupDirs_r, Pathname dir_r)
Remember valid lookup dirs.
Definition: econfdict.cc:115
const std::optional< Pathname > & etcDir() const
Definition: econfdict.cc:50
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:126
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:182
Definition: ansi.h:854
Provide access to the prioritized list of files and drop-ins to read and merge for a specific config ...
Definition: econfdict.cc:36
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
static bool isSet(const PathInfo &file_r)
An empty path denotes the unset value.
Definition: econfdict.cc:122
std::optional< Pathname > _etcDir
system configuration: /etc
Definition: econfdict.cc:148
bool empty() const
Test for an empty path.
Definition: Pathname.h:117
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:286
static Pathname _defaultDistconfDir
APIConfig(LIBZYPP_ZYPPCONFDIR) but amendable for Testing.
Definition: econfdict.cc:39
std::optional< Pathname > _usrDir
vendor configuration: distconfdir (APIConfig(LIBZYPP_ZYPPCONFDIR))
Definition: econfdict.cc:149
static void handOutIf(std::vector< Pathname > &ret_r, const PathInfo &file_r)
Store set values in ret_r.
Definition: econfdict.cc:138
#define _(MSG)
Definition: Gettext.h:39
static Pathname defaultDistconfDir()
Where the vendor configuration files live (APIConfig(LIBZYPP_ZYPPCONFDIR))
Definition: econfdict.cc:168
const std::optional< Pathname > & usrDir() const
Definition: econfdict.cc:51
ConfigurationContext(std::optional< Pathname > etcDir_r, std::optional< Pathname > usrDir_r)
Definition: econfdict.cc:45
Parses a INI file and offers its structure as a dictionary.
Definition: inidict.h:41
#define pMIL
Definition: LogTools.h:305
bool hasSuffix(const C_Str &str_r, const C_Str &suffix_r)
Return whether str_r has suffix suffix_r.
Definition: String.h:1112
std::vector< Pathname > getConfigFiles(const std::string &stem_r, const Pathname &root_r=Pathname("/")) const
Definition: econfdict.cc:53
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
#define pDBG
Definition: LogTools.h:304
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition: PathInfo.cc:612
std::string sprint(Args &&... args)
Print words as string.
Definition: LogTools.h:266
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