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