* apt-pkg/aptconfiguration.cc:
[ntk/apt.git] / apt-pkg / aptconfiguration.cc
CommitLineData
e878aedb
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
7
8 ##################################################################### */
9 /*}}}*/
10// Include Files /*{{{*/
e878aedb
DK
11#include <apt-pkg/aptconfiguration.h>
12#include <apt-pkg/configuration.h>
9f9717fa 13#include <apt-pkg/error.h>
d7cf5923
DK
14#include <apt-pkg/fileutl.h>
15#include <apt-pkg/macros.h>
16#include <apt-pkg/strutl.h>
e878aedb 17
3f2d77b5
DK
18#include <sys/types.h>
19#include <dirent.h>
20
8bd02d8b 21#include <algorithm>
3f2d77b5
DK
22#include <string>
23#include <vector>
e878aedb
DK
24 /*}}}*/
25namespace APT {
26// getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/
27// ---------------------------------------------------------------------
28/* return a vector of compression types in the prefered order. */
29std::vector<std::string>
30const Configuration::getCompressionTypes(bool const &Cached) {
31 static std::vector<std::string> types;
32 if (types.empty() == false) {
33 if (Cached == true)
34 return types;
35 else
36 types.clear();
37 }
38
8bd02d8b
DK
39 // setup the defaults for the compressiontypes => method mapping
40 _config->CndSet("Acquire::CompressionTypes::bz2","bzip2");
b2430e6d 41 _config->CndSet("Acquire::CompressionTypes::xz","xz");
8bd02d8b
DK
42 _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
43 _config->CndSet("Acquire::CompressionTypes::gz","gzip");
44
e878aedb
DK
45 // Set default application paths to check for optional compression types
46 _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
b2430e6d 47 _config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
e878aedb
DK
48 _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
49
8bd02d8b
DK
50 // accept non-list order as override setting for config settings on commandline
51 std::string const overrideOrder = _config->Find("Acquire::CompressionTypes::Order","");
52 if (overrideOrder.empty() == false)
53 types.push_back(overrideOrder);
e878aedb 54
8bd02d8b
DK
55 // load the order setting into our vector
56 std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order");
57 for (std::vector<std::string>::const_iterator o = order.begin();
58 o != order.end(); o++) {
59 if ((*o).empty() == true)
60 continue;
61 // ignore types we have no method ready to use
62 if (_config->Exists(string("Acquire::CompressionTypes::").append(*o)) == false)
63 continue;
64 // ignore types we have no app ready to use
65 string const appsetting = string("Dir::Bin::").append(*o);
66 if (_config->Exists(appsetting) == true) {
67 std::string const app = _config->FindFile(appsetting.c_str(), "");
68 if (app.empty() == false && FileExists(app) == false)
69 continue;
70 }
71 types.push_back(*o);
e878aedb
DK
72 }
73
8bd02d8b 74 // move again over the option tree to add all missing compression types
e878aedb
DK
75 ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes");
76 if (Types != 0)
77 Types = Types->Child;
78
79 for (; Types != 0; Types = Types->Next) {
8bd02d8b
DK
80 if (Types->Tag == "Order" || Types->Tag.empty() == true)
81 continue;
82 // ignore types we already have in the vector
83 if (std::find(types.begin(),types.end(),Types->Tag) != types.end())
84 continue;
85 // ignore types we have no app ready to use
e878aedb 86 string const appsetting = string("Dir::Bin::").append(Types->Value);
e878aedb
DK
87 if (appsetting.empty() == false && _config->Exists(appsetting) == true) {
88 std::string const app = _config->FindFile(appsetting.c_str(), "");
89 if (app.empty() == false && FileExists(app) == false)
90 continue;
91 }
92 types.push_back(Types->Tag);
93 }
94
5d885723
DK
95 // add the special "uncompressed" type
96 if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
97 {
98 string const uncompr = _config->FindFile("Dir::Bin::uncompressed", "");
99 if (uncompr.empty() == true || FileExists(uncompr) == true)
100 types.push_back("uncompressed");
101 }
102
e878aedb
DK
103 return types;
104}
105 /*}}}*/
45df0ad2
DK
106// GetLanguages - Return Vector of Language Codes /*{{{*/
107// ---------------------------------------------------------------------
108/* return a vector of language codes in the prefered order.
109 the special word "environment" will be replaced with the long and the short
110 code of the local settings and it will be insured that this will not add
111 duplicates. So in an german local the setting "environment, de_DE, en, de"
112 will result in "de_DE, de, en".
113 The special word "none" is the stopcode for the not-All code vector */
114std::vector<std::string> const Configuration::getLanguages(bool const &All,
d7cf5923 115 bool const &Cached, char const ** const Locale) {
45df0ad2
DK
116 using std::string;
117
118 // The detection is boring and has a lot of cornercases,
119 // so we cache the results to calculated it only once.
120 std::vector<string> static allCodes;
121 std::vector<string> static codes;
122
123 // we have something in the cache
124 if (codes.empty() == false || allCodes.empty() == false) {
125 if (Cached == true) {
126 if(All == true && allCodes.empty() == false)
127 return allCodes;
128 else
129 return codes;
130 } else {
131 allCodes.clear();
132 codes.clear();
133 }
134 }
135
3f2d77b5
DK
136 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
137 // so they will be all included in the Cache.
138 std::vector<string> builtin;
139 DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str());
140 if (D != 0) {
141 builtin.push_back("none");
142 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
143 string const name = Ent->d_name;
144 size_t const foundDash = name.rfind("-");
145 size_t const foundUnderscore = name.rfind("_");
146 if (foundDash == string::npos || foundUnderscore == string::npos ||
147 foundDash <= foundUnderscore ||
148 name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation")
149 continue;
150 string const c = name.substr(foundDash+1);
151 if (unlikely(c.empty() == true) || c == "en")
152 continue;
153 // Skip unusual files, like backups or that alike
154 string::const_iterator s = c.begin();
155 for (;s != c.end(); ++s) {
156 if (isalpha(*s) == 0)
157 break;
158 }
159 if (s != c.end())
160 continue;
161 if (std::find(builtin.begin(), builtin.end(), c) != builtin.end())
162 continue;
163 builtin.push_back(c);
164 }
165 }
cf0e078c 166 closedir(D);
3f2d77b5 167
45df0ad2
DK
168 // FIXME: Remove support for the old APT::Acquire::Translation
169 // it was undocumented and so it should be not very widthly used
170 string const oldAcquire = _config->Find("APT::Acquire::Translation","");
171 if (oldAcquire.empty() == false && oldAcquire != "environment") {
9f9717fa
DK
172 // TRANSLATORS: the two %s are APT configuration options
173 _error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
174 "APT::Acquire::Translation", "Acquire::Languages");
45df0ad2
DK
175 if (oldAcquire != "none")
176 codes.push_back(oldAcquire);
3f2d77b5 177 codes.push_back("en");
d7cf5923 178 allCodes = codes;
3f2d77b5
DK
179 for (std::vector<string>::const_iterator b = builtin.begin();
180 b != builtin.end(); ++b)
181 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
182 allCodes.push_back(*b);
183 if (All == true)
184 return allCodes;
185 else
186 return codes;
45df0ad2
DK
187 }
188
ab53c018
DK
189 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
190 // we extract both, a long and a short code and then we will
191 // check if we actually need both (rare) or if the short is enough
192 string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : *Locale);
193 size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
194 size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3);
195
196 string const envLong = envMsg.substr(0,lenLong);
197 string const envShort = envLong.substr(0,lenShort);
198
199 // It is very likely we will need the environment codes later,
d7cf5923
DK
200 // so let us generate them now from LC_MESSAGES and LANGUAGE
201 std::vector<string> environment;
eb3947c6
DK
202 if (envShort != "C") {
203 // take care of LC_MESSAGES
ab53c018 204 if (envLong != envShort)
eb3947c6
DK
205 environment.push_back(envLong);
206 environment.push_back(envShort);
207 // take care of LANGUAGE
208 const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
209 string envLang = Locale == 0 ? language_env : *(Locale+1);
210 if (envLang.empty() == false) {
211 std::vector<string> env = VectorizeString(envLang,':');
212 short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
213 for (std::vector<string>::const_iterator e = env.begin();
214 e != env.end() && addedLangs < 3; ++e) {
215 if (unlikely(e->empty() == true) || *e == "en")
216 continue;
217 if (*e == envLong || *e == envShort)
218 continue;
219 if (std::find(environment.begin(), environment.end(), *e) != environment.end())
d7cf5923 220 continue;
eb3947c6
DK
221 ++addedLangs;
222 environment.push_back(*e);
d7cf5923 223 }
d7cf5923 224 }
eb3947c6
DK
225 } else {
226 environment.push_back("en");
d7cf5923
DK
227 }
228
45df0ad2
DK
229 // Support settings like Acquire::Translation=none on the command line to
230 // override the configuration settings vector of languages.
231 string const forceLang = _config->Find("Acquire::Languages","");
232 if (forceLang.empty() == false) {
233 if (forceLang == "environment") {
d7cf5923 234 codes = environment;
45df0ad2
DK
235 } else if (forceLang != "none")
236 codes.push_back(forceLang);
d7cf5923 237 allCodes = codes;
3f2d77b5
DK
238 for (std::vector<string>::const_iterator b = builtin.begin();
239 b != builtin.end(); ++b)
240 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
241 allCodes.push_back(*b);
242 if (All == true)
243 return allCodes;
244 else
245 return codes;
45df0ad2
DK
246 }
247
eb3947c6
DK
248 // cornercase: LANG=C, so we use only "en" Translation
249 if (envShort == "C") {
250 allCodes = codes = environment;
251 allCodes.insert(allCodes.end(), builtin.begin(), builtin.end());
252 if (All == true)
253 return allCodes;
254 else
255 return codes;
256 }
257
45df0ad2
DK
258 std::vector<string> const lang = _config->FindVector("Acquire::Languages");
259 // the default setting -> "environment, en"
260 if (lang.empty() == true) {
d7cf5923 261 codes = environment;
45df0ad2
DK
262 if (envShort != "en")
263 codes.push_back("en");
d7cf5923 264 allCodes = codes;
3f2d77b5
DK
265 for (std::vector<string>::const_iterator b = builtin.begin();
266 b != builtin.end(); ++b)
267 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
268 allCodes.push_back(*b);
269 if (All == true)
270 return allCodes;
271 else
272 return codes;
45df0ad2
DK
273 }
274
275 // the configs define the order, so add the environment
276 // then needed and ensure the codes are not listed twice.
277 bool noneSeen = false;
278 for (std::vector<string>::const_iterator l = lang.begin();
279 l != lang.end(); l++) {
280 if (*l == "environment") {
d7cf5923
DK
281 for (std::vector<string>::const_iterator e = environment.begin();
282 e != environment.end(); ++e) {
283 if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end())
284 continue;
45df0ad2 285 if (noneSeen == false)
d7cf5923
DK
286 codes.push_back(*e);
287 allCodes.push_back(*e);
45df0ad2
DK
288 }
289 continue;
290 } else if (*l == "none") {
291 noneSeen = true;
292 continue;
d7cf5923 293 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
45df0ad2
DK
294 continue;
295
296 if (noneSeen == false)
297 codes.push_back(*l);
298 allCodes.push_back(*l);
299 }
3f2d77b5
DK
300
301 for (std::vector<string>::const_iterator b = builtin.begin();
302 b != builtin.end(); ++b)
303 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
304 allCodes.push_back(*b);
305
45df0ad2
DK
306 if (All == true)
307 return allCodes;
308 else
309 return codes;
310}
311 /*}}}*/
5dd4c8b8
DK
312// getArchitectures - Return Vector of prefered Architectures /*{{{*/
313std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
314 using std::string;
315
316 std::vector<string> static archs;
317 if (likely(Cached == true) && archs.empty() == false)
318 return archs;
319
5dd4c8b8 320 archs = _config->FindVector("APT::Architectures");
3152f4aa
DK
321 string const arch = _config->Find("APT::Architecture");
322 if (unlikely(arch.empty() == true))
323 return archs;
324
5dd4c8b8
DK
325 if (archs.empty() == true ||
326 std::find(archs.begin(), archs.end(), arch) == archs.end())
327 archs.push_back(arch);
3152f4aa
DK
328
329 // erase duplicates and empty strings
330 for (std::vector<string>::reverse_iterator a = archs.rbegin();
331 a != archs.rend(); ++a) {
332 if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
333 archs.erase(a.base()-1);
334 if (a == archs.rend())
335 break;
336 }
337
5dd4c8b8
DK
338 return archs;
339}
340 /*}}}*/
341// checkArchitecture - are we interested in the given Architecture? /*{{{*/
342bool const Configuration::checkArchitecture(std::string const &Arch) {
343 if (Arch == "all")
344 return true;
345 std::vector<std::string> const archs = getArchitectures(true);
346 return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
347}
348 /*}}}*/
e878aedb 349}