25ededf23d4b1c8c958d3fb9d5ccf7683f387d97
[platform/upstream/libzypp.git] / zypp / parser / RepoFileReader.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/repo/RepoFileReader.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/String.h"
15 #include "zypp/base/Regex.h"
16 #include "zypp/base/InputStream.h"
17 #include "zypp/base/UserRequestException.h"
18
19 #include "zypp/parser/IniDict.h"
20 #include "zypp/parser/RepoFileReader.h"
21
22 using std::endl;
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 {
27   ///////////////////////////////////////////////////////////////////
28   namespace parser
29   {
30     ///////////////////////////////////////////////////////////////////
31     namespace {
32
33       ///////////////////////////////////////////////////////////////////
34       /// \class RepoFileParser
35       /// \brief Modified \ref IniDict to allow parsing multiple 'baseurl=' entries
36       ///////////////////////////////////////////////////////////////////
37       class RepoFileParser : public IniDict
38       {
39       public:
40         RepoFileParser( const InputStream & is_r )
41         { read( is_r ); }
42
43         using IniDict::consume; // don't hide overloads we don't redefine here
44
45         virtual void consume( const std::string & section_r, const std::string & key_r, const std::string & value_r )
46         {
47           if ( key_r == "baseurl" )
48           {
49             _inMultiline = MultiLine::baseurl;
50             _baseurls[section_r].push_back( Url(value_r) );
51           }
52           else if ( key_r == "gpgkey" )
53           {
54             _inMultiline = MultiLine::gpgkey;
55             legacyStoreUrl( _gpgkeys[section_r], value_r );
56           }
57           else
58           {
59             _inMultiline = MultiLine::none;
60             IniDict::consume( section_r, key_r, value_r );
61           }
62         }
63
64         virtual void garbageLine( const std::string & section_r, const std::string & line_r )
65         {
66           switch ( _inMultiline )
67           {
68             case MultiLine::baseurl:
69               _baseurls[section_r].push_back( Url(line_r) );
70               break;
71
72             case MultiLine::gpgkey:
73               legacyStoreUrl( _gpgkeys[section_r], line_r );
74               break;
75
76             case MultiLine::none:
77               IniDict::garbageLine( section_r, line_r );        // throw
78               break;
79           }
80         }
81
82         std::list<Url> & baseurls( const std::string & section_r )
83         { return _baseurls[section_r]; }
84
85         std::list<Url> & gpgkeys( const std::string & section_r )
86         { return _gpgkeys[section_r]; }
87
88       private:
89         void legacyStoreUrl( std::list<Url> & store_r, const std::string & line_r )
90         {
91           // Legacy:
92           //    commit 4ef65a442038caf7a1e310bc719e329b34dbdb67
93           //    - split the gpgkey line and take the first one as url to avoid
94           //      crash when creating an url from the line, as Fedora hat the
95           //      *BRILLIANT* idea of using more than one url per line.
96           std::vector<std::string> keys;
97           str::split( line_r, std::back_inserter(keys) );
98           for ( auto && str : keys )
99             store_r.push_back( Url(std::move(str)) );
100         }
101
102         enum class MultiLine { none, baseurl, gpgkey };
103         MultiLine _inMultiline = MultiLine::none;
104
105         std::map<std::string,std::list<Url>> _baseurls;
106         std::map<std::string,std::list<Url>> _gpgkeys;
107       };
108
109     } //namespace
110     ///////////////////////////////////////////////////////////////////
111
112     /**
113    * \short List of RepoInfo's from a file.
114    * \param file pathname of the file to read.
115    */
116     static void repositories_in_stream( const InputStream &is,
117                                         const RepoFileReader::ProcessRepo &callback,
118                                         const ProgressData::ReceiverFnc &progress )
119     {
120       RepoFileParser dict(is);
121       for_( its, dict.sectionsBegin(), dict.sectionsEnd() )
122       {
123         RepoInfo info;
124         info.setAlias(*its);
125         std::string proxy;
126         std::string proxyport;
127
128         for_( it, dict.entriesBegin(*its), dict.entriesEnd(*its) )
129         {
130           //MIL << (*it).first << endl;
131           if (it->first == "name" )
132             info.setName(it-> second);
133           else if ( it->first == "enabled" )
134             info.setEnabled( str::strToTrue( it->second ) );
135           else if ( it->first == "priority" )
136             info.setPriority( str::strtonum<unsigned>( it->second ) );
137           else if ( it->first == "path" )
138             info.setPath( Pathname(it->second) );
139           else if ( it->first == "type" )
140             info.setType(repo::RepoType(it->second));
141           else if ( it->first == "autorefresh" )
142             info.setAutorefresh( str::strToTrue( it->second ) );
143           else if ( it->first == "mirrorlist" && !it->second.empty())
144             info.setMirrorListUrl(Url(it->second));
145           else if ( it->first == "gpgcheck" )
146             info.setGpgCheck( str::strToTriBool( it->second ) );
147           else if ( it->first == "repo_gpgcheck" )
148             info.setRepoGpgCheck( str::strToTrue( it->second ) );
149           else if ( it->first == "pkg_gpgcheck" )
150             info.setPkgGpgCheck( str::strToTrue( it->second ) );
151           else if ( it->first == "keeppackages" )
152             info.setKeepPackages( str::strToTrue( it->second ) );
153           else if ( it->first == "service" )
154             info.setService( it->second );
155           else if ( it->first == "proxy" )
156           {
157             // Translate it into baseurl queryparams
158             // NOTE: The hack here does not add proxy to mirrorlist urls but the
159             //       original code worked without complains, so keep it for now.
160             static const str::regex ex( ":[0-9]+$" );   // portspec
161             str::smatch what;
162             if ( str::regex_match( it->second, what, ex ) )
163             {
164               proxy = it->second.substr( 0, it->second.size() - what[0].size() );
165               proxyport = what[0].substr( 1 );
166             }
167             else
168             {
169               proxy = it->second;
170             }
171           }
172           else
173             ERR << "Unknown attribute in [" << *its << "]: " << it->first << "=" << it->second << " ignored" << endl;
174         }
175
176         for ( auto & url : dict.baseurls( *its ) )
177         {
178           if ( ! proxy.empty() && url.getQueryParam( "proxy" ).empty() )
179           {
180             url.setQueryParam( "proxy", proxy );
181             url.setQueryParam( "proxyport", proxyport );
182           }
183           info.addBaseUrl( url );
184         }
185
186         info.setGpgKeyUrls( std::move(dict.gpgkeys( *its )) );
187
188         info.setFilepath(is.path());
189         MIL << info << endl;
190         // add it to the list.
191         callback(info);
192         //if (!progress.tick())
193         //  ZYPP_THROW(AbortRequestException());
194       }
195     }
196
197     ///////////////////////////////////////////////////////////////////
198     //
199     //  CLASS NAME : RepoFileReader
200     //
201     ///////////////////////////////////////////////////////////////////
202
203     RepoFileReader::RepoFileReader( const Pathname & repo_file,
204                                     const ProcessRepo & callback,
205                                     const ProgressData::ReceiverFnc &progress )
206       : _callback(callback)
207     {
208       repositories_in_stream(InputStream(repo_file), _callback, progress);
209     }
210
211     RepoFileReader::RepoFileReader( const InputStream &is,
212                                     const ProcessRepo & callback,
213                                     const ProgressData::ReceiverFnc &progress )
214       : _callback(callback)
215     {
216       repositories_in_stream(is, _callback, progress);
217     }
218
219     RepoFileReader::~RepoFileReader()
220     {}
221
222
223     std::ostream & operator<<( std::ostream & str, const RepoFileReader & obj )
224     {
225       return str;
226     }
227
228   } // namespace parser
229   ///////////////////////////////////////////////////////////////////
230 } // namespace zypp
231 ///////////////////////////////////////////////////////////////////