support every compression we have a compressor configured
[ntk/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::xz","xz");
42 _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
43 _config->CndSet("Acquire::CompressionTypes::gz","gzip");
44
45 setDefaultConfigurationForCompressors();
46
47 // accept non-list order as override setting for config settings on commandline
48 std::string const overrideOrder = _config->Find("Acquire::CompressionTypes::Order","");
49 if (overrideOrder.empty() == false)
50 types.push_back(overrideOrder);
51
52 // load the order setting into our vector
53 std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order");
54 for (std::vector<std::string>::const_iterator o = order.begin();
55 o != order.end(); o++) {
56 if ((*o).empty() == true)
57 continue;
58 // ignore types we have no method ready to use
59 if (_config->Exists(string("Acquire::CompressionTypes::").append(*o)) == false)
60 continue;
61 // ignore types we have no app ready to use
62 string const appsetting = string("Dir::Bin::").append(*o);
63 if (_config->Exists(appsetting) == true) {
64 std::string const app = _config->FindFile(appsetting.c_str(), "");
65 if (app.empty() == false && FileExists(app) == false)
66 continue;
67 }
68 types.push_back(*o);
69 }
70
71 // move again over the option tree to add all missing compression types
72 ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes");
73 if (Types != 0)
74 Types = Types->Child;
75
76 for (; Types != 0; Types = Types->Next) {
77 if (Types->Tag == "Order" || Types->Tag.empty() == true)
78 continue;
79 // ignore types we already have in the vector
80 if (std::find(types.begin(),types.end(),Types->Tag) != types.end())
81 continue;
82 // ignore types we have no app ready to use
83 string const appsetting = string("Dir::Bin::").append(Types->Value);
84 if (appsetting.empty() == false && _config->Exists(appsetting) == true) {
85 std::string const app = _config->FindFile(appsetting.c_str(), "");
86 if (app.empty() == false && FileExists(app) == false)
87 continue;
88 }
89 types.push_back(Types->Tag);
90 }
91
92 // add the special "uncompressed" type
93 if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
94 {
95 string const uncompr = _config->FindFile("Dir::Bin::uncompressed", "");
96 if (uncompr.empty() == true || FileExists(uncompr) == true)
97 types.push_back("uncompressed");
98 }
99
100 return types;
101 }
102 /*}}}*/
103 // GetLanguages - Return Vector of Language Codes /*{{{*/
104 // ---------------------------------------------------------------------
105 /* return a vector of language codes in the prefered order.
106 the special word "environment" will be replaced with the long and the short
107 code of the local settings and it will be insured that this will not add
108 duplicates. So in an german local the setting "environment, de_DE, en, de"
109 will result in "de_DE, de, en".
110 The special word "none" is the stopcode for the not-All code vector */
111 std::vector<std::string> const Configuration::getLanguages(bool const &All,
112 bool const &Cached, char const ** const Locale) {
113 using std::string;
114
115 // The detection is boring and has a lot of cornercases,
116 // so we cache the results to calculated it only once.
117 std::vector<string> static allCodes;
118 std::vector<string> static codes;
119
120 // we have something in the cache
121 if (codes.empty() == false || allCodes.empty() == false) {
122 if (Cached == true) {
123 if(All == true && allCodes.empty() == false)
124 return allCodes;
125 else
126 return codes;
127 } else {
128 allCodes.clear();
129 codes.clear();
130 }
131 }
132
133 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
134 // so they will be all included in the Cache.
135 std::vector<string> builtin;
136 DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str());
137 if (D != 0) {
138 builtin.push_back("none");
139 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
140 string const name = Ent->d_name;
141 size_t const foundDash = name.rfind("-");
142 size_t const foundUnderscore = name.rfind("_");
143 if (foundDash == string::npos || foundUnderscore == string::npos ||
144 foundDash <= foundUnderscore ||
145 name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation")
146 continue;
147 string const c = name.substr(foundDash+1);
148 if (unlikely(c.empty() == true) || c == "en")
149 continue;
150 // Skip unusual files, like backups or that alike
151 string::const_iterator s = c.begin();
152 for (;s != c.end(); ++s) {
153 if (isalpha(*s) == 0)
154 break;
155 }
156 if (s != c.end())
157 continue;
158 if (std::find(builtin.begin(), builtin.end(), c) != builtin.end())
159 continue;
160 builtin.push_back(c);
161 }
162 }
163 closedir(D);
164
165 // FIXME: Remove support for the old APT::Acquire::Translation
166 // it was undocumented and so it should be not very widthly used
167 string const oldAcquire = _config->Find("APT::Acquire::Translation","");
168 if (oldAcquire.empty() == false && oldAcquire != "environment") {
169 // TRANSLATORS: the two %s are APT configuration options
170 _error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
171 "APT::Acquire::Translation", "Acquire::Languages");
172 if (oldAcquire != "none")
173 codes.push_back(oldAcquire);
174 codes.push_back("en");
175 allCodes = codes;
176 for (std::vector<string>::const_iterator b = builtin.begin();
177 b != builtin.end(); ++b)
178 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
179 allCodes.push_back(*b);
180 if (All == true)
181 return allCodes;
182 else
183 return codes;
184 }
185
186 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
187 // we extract both, a long and a short code and then we will
188 // check if we actually need both (rare) or if the short is enough
189 string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : *Locale);
190 size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
191 size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3);
192
193 string const envLong = envMsg.substr(0,lenLong);
194 string const envShort = envLong.substr(0,lenShort);
195
196 // It is very likely we will need the environment codes later,
197 // so let us generate them now from LC_MESSAGES and LANGUAGE
198 std::vector<string> environment;
199 if (envShort != "C") {
200 // take care of LC_MESSAGES
201 if (envLong != envShort)
202 environment.push_back(envLong);
203 environment.push_back(envShort);
204 // take care of LANGUAGE
205 const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
206 string envLang = Locale == 0 ? language_env : *(Locale+1);
207 if (envLang.empty() == false) {
208 std::vector<string> env = VectorizeString(envLang,':');
209 short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
210 for (std::vector<string>::const_iterator e = env.begin();
211 e != env.end() && addedLangs < 3; ++e) {
212 if (unlikely(e->empty() == true) || *e == "en")
213 continue;
214 if (*e == envLong || *e == envShort)
215 continue;
216 if (std::find(environment.begin(), environment.end(), *e) != environment.end())
217 continue;
218 ++addedLangs;
219 environment.push_back(*e);
220 }
221 }
222 } else {
223 environment.push_back("en");
224 }
225
226 // Support settings like Acquire::Translation=none on the command line to
227 // override the configuration settings vector of languages.
228 string const forceLang = _config->Find("Acquire::Languages","");
229 if (forceLang.empty() == false) {
230 if (forceLang == "environment") {
231 codes = environment;
232 } else if (forceLang != "none")
233 codes.push_back(forceLang);
234 allCodes = codes;
235 for (std::vector<string>::const_iterator b = builtin.begin();
236 b != builtin.end(); ++b)
237 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
238 allCodes.push_back(*b);
239 if (All == true)
240 return allCodes;
241 else
242 return codes;
243 }
244
245 // cornercase: LANG=C, so we use only "en" Translation
246 if (envShort == "C") {
247 allCodes = codes = environment;
248 allCodes.insert(allCodes.end(), builtin.begin(), builtin.end());
249 if (All == true)
250 return allCodes;
251 else
252 return codes;
253 }
254
255 std::vector<string> const lang = _config->FindVector("Acquire::Languages");
256 // the default setting -> "environment, en"
257 if (lang.empty() == true) {
258 codes = environment;
259 if (envShort != "en")
260 codes.push_back("en");
261 allCodes = codes;
262 for (std::vector<string>::const_iterator b = builtin.begin();
263 b != builtin.end(); ++b)
264 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
265 allCodes.push_back(*b);
266 if (All == true)
267 return allCodes;
268 else
269 return codes;
270 }
271
272 // the configs define the order, so add the environment
273 // then needed and ensure the codes are not listed twice.
274 bool noneSeen = false;
275 for (std::vector<string>::const_iterator l = lang.begin();
276 l != lang.end(); l++) {
277 if (*l == "environment") {
278 for (std::vector<string>::const_iterator e = environment.begin();
279 e != environment.end(); ++e) {
280 if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end())
281 continue;
282 if (noneSeen == false)
283 codes.push_back(*e);
284 allCodes.push_back(*e);
285 }
286 continue;
287 } else if (*l == "none") {
288 noneSeen = true;
289 continue;
290 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
291 continue;
292
293 if (noneSeen == false)
294 codes.push_back(*l);
295 allCodes.push_back(*l);
296 }
297
298 for (std::vector<string>::const_iterator b = builtin.begin();
299 b != builtin.end(); ++b)
300 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
301 allCodes.push_back(*b);
302
303 if (All == true)
304 return allCodes;
305 else
306 return codes;
307 }
308 /*}}}*/
309 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
310 std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
311 using std::string;
312
313 std::vector<string> static archs;
314 if (likely(Cached == true) && archs.empty() == false)
315 return archs;
316
317 archs = _config->FindVector("APT::Architectures");
318 string const arch = _config->Find("APT::Architecture");
319 if (unlikely(arch.empty() == true))
320 return archs;
321
322 if (archs.empty() == true ||
323 std::find(archs.begin(), archs.end(), arch) == archs.end())
324 archs.push_back(arch);
325
326 // erase duplicates and empty strings
327 for (std::vector<string>::reverse_iterator a = archs.rbegin();
328 a != archs.rend(); ++a) {
329 if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
330 archs.erase(a.base()-1);
331 if (a == archs.rend())
332 break;
333 }
334
335 return archs;
336 }
337 /*}}}*/
338 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
339 bool const Configuration::checkArchitecture(std::string const &Arch) {
340 if (Arch == "all")
341 return true;
342 std::vector<std::string> const archs = getArchitectures(true);
343 return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
344 }
345 /*}}}*/
346 // setDefaultConfigurationForCompressors /*{{{*/
347 void Configuration::setDefaultConfigurationForCompressors() {
348 // Set default application paths to check for optional compression types
349 _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
350 _config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
351 _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
352 }
353 /*}}}*/
354 // getCompressors - Return Vector of usbale compressors /*{{{*/
355 // ---------------------------------------------------------------------
356 /* return a vector of compressors used by apt-ftparchive in the
357 multicompress functionality or to detect data.tar files */
358 std::vector<APT::Configuration::Compressor>
359 const Configuration::getCompressors(bool const Cached) {
360 static std::vector<APT::Configuration::Compressor> compressors;
361 if (compressors.empty() == false) {
362 if (Cached == true)
363 return compressors;
364 else
365 compressors.clear();
366 }
367
368 setDefaultConfigurationForCompressors();
369
370 compressors.push_back(Compressor(".", "", "", "", "", 1));
371 if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->FindFile("Dir::Bin::gzip")) == true)
372 compressors.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
373 if (_config->Exists("Dir::Bin::bzip2") == false || FileExists(_config->FindFile("Dir::Bin::bzip2")) == true)
374 compressors.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
375 if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->FindFile("Dir::Bin::lzma")) == true)
376 compressors.push_back(Compressor("lzma",".lzma","lzma","-9","-d",4));
377 if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->FindFile("Dir::Bin::xz")) == true)
378 compressors.push_back(Compressor("xz",".xz","xz","-6","-d",5));
379
380 std::vector<std::string> const comp = _config->FindVector("APT::Compressor");
381 for (std::vector<std::string>::const_iterator c = comp.begin();
382 c != comp.end(); ++c) {
383 if (*c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz")
384 continue;
385 compressors.push_back(Compressor(c->c_str(), std::string(".").append(*c).c_str(), c->c_str(), "-9", "-d", 100));
386 }
387
388 return compressors;
389 }
390 /*}}}*/
391 // getCompressorExtensions - supported data.tar extensions /*{{{*/
392 // ---------------------------------------------------------------------
393 /* */
394 std::vector<std::string> const Configuration::getCompressorExtensions() {
395 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
396 std::vector<std::string> ext;
397 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
398 c != compressors.end(); ++c)
399 if (c->Extension.empty() == false && c->Extension != ".")
400 ext.push_back(c->Extension);
401 return ext;
402 }
403 /*}}}*/
404 // Compressor constructor /*{{{*/
405 // ---------------------------------------------------------------------
406 /* */
407 Configuration::Compressor::Compressor(char const *name, char const *extension,
408 char const *binary,
409 char const *compressArg, char const *uncompressArg,
410 unsigned short const cost) {
411 std::string const config = string("APT:Compressor::").append(name).append("::");
412 Name = _config->Find(std::string(config).append("Name"), name);
413 Extension = _config->Find(std::string(config).append("Extension"), extension);
414 Binary = _config->Find(std::string(config).append("Binary"), binary);
415 Cost = _config->FindI(std::string(config).append("Cost"), cost);
416 std::string const compConf = std::string(config).append("CompressArg");
417 if (_config->Exists(compConf) == true)
418 CompressArgs = _config->FindVector(compConf);
419 else if (compressArg != NULL)
420 CompressArgs.push_back(compressArg);
421 std::string const uncompConf = std::string(config).append("UncompressArg");
422 if (_config->Exists(uncompConf) == true)
423 UncompressArgs = _config->FindVector(uncompConf);
424 else if (uncompressArg != NULL)
425 UncompressArgs.push_back(uncompressArg);
426 }
427 /*}}}*/
428 }