1 # Copyright © 2007-2022 Guillem Jover <guillem@debian.org>
2 # Copyright © 2010 Raphaël Hertzog <hertzog@debian.org>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 Dpkg::Compression - simple database of available compression methods
25 This modules provides a few public functions and a public regex to
26 interact with the set of supported compression methods.
30 package Dpkg
::Compression
2.01;
36 compression_is_supported
38 compression_get_property
39 compression_guess_from_filename
40 compression_get_file_extension_regex
41 compression_get_file_extension
42 compression_get_default
43 compression_set_default
44 compression_get_default_level
45 compression_set_default_level
48 compression_is_valid_level
49 compression_get_threads
50 compression_set_threads
51 compression_get_cmdline_compress
52 compression_get_cmdline_decompress
55 use Exporter
qw(import);
57 use List
::Util
qw(any);
59 use Dpkg
::ErrorHandling
;
65 comp_prog
=> [ 'gzip', '-n' ],
66 decomp_prog
=> [ 'gunzip' ],
71 comp_prog
=> [ 'bzip2' ],
72 decomp_prog
=> [ 'bunzip2' ],
77 comp_prog
=> [ 'xz', '--format=lzma' ],
78 decomp_prog
=> [ 'unxz', '--format=lzma' ],
83 comp_prog
=> [ 'xz' ],
84 decomp_prog
=> [ 'unxz' ],
89 # The gzip --rsyncable option is not universally supported, so we need to
90 # conditionally use it. Ideally we would invoke 'gzip --help' and check
91 # whether the option is supported, but that would imply forking and executing
92 # that process for any module that ends up loading this one, which is not
93 # acceptable performance-wise. Instead we will approximate it by osname, which
94 # is not ideal, but better than nothing.
96 # Requires GNU gzip >= 1.7 for the --rsyncable option. On AIX GNU gzip is
97 # too old. On the BSDs they use their own implementation based on zlib,
98 # which does not currently support the --rsyncable option.
99 if (any
{ $Config{osname
} eq $_ } qw(linux gnu solaris)) {
100 push @
{$COMP{gzip
}{comp_prog
}}, '--rsyncable';
103 my $default_compression = 'xz';
104 my $default_compression_level = undef;
105 my $default_compression_threads = 0;
107 my $regex = join '|', map { $_->{file_ext
} } values %COMP;
108 my $compression_re_file_ext = qr/(?:$regex)/;
114 =item @list = compression_get_list()
116 Returns a list of supported compression methods (sorted alphabetically).
120 sub compression_get_list
{
121 my @list = sort keys %COMP;
125 =item compression_is_supported($comp)
127 Returns a boolean indicating whether the give compression method is
132 sub compression_is_supported
{
135 return exists $COMP{$comp};
138 =item compression_get_property($comp, $property)
140 Returns the requested property of the compression method. Returns undef if
141 either the property or the compression method doesn't exist. Valid
142 properties currently include "file_ext" for the file extension,
143 "default_level" for the default compression level,
144 "comp_prog" for the name of the compression program and "decomp_prog" for
145 the name of the decompression program.
147 This function is deprecated, please switch to one of the new specialized
152 sub compression_get_property
{
153 my ($comp, $property) = @_;
155 #warnings::warnif('deprecated',
156 # 'Dpkg::Compression::compression_get_property() is deprecated, ' .
157 # 'use one of the specialized getters instead');
158 return unless compression_is_supported
($comp);
159 return $COMP{$comp}{$property} if exists $COMP{$comp}{$property};
163 =item compression_guess_from_filename($filename)
165 Returns the compression method that is likely used on the indicated
166 filename based on its file extension.
170 sub compression_guess_from_filename
{
171 my $filename = shift;
172 foreach my $comp (compression_get_list
()) {
173 my $ext = $COMP{$comp}{file_ext
};
174 if ($filename =~ /^(.*)\.\Q$ext\E$/) {
181 =item $regex = compression_get_file_extension_regex()
183 Returns a regex that matches a file extension of a file compressed with
184 one of the supported compression methods.
188 sub compression_get_file_extension_regex
{
189 return $compression_re_file_ext;
192 =item $ext = compression_get_file_extension($comp)
194 Return the file extension for the compressor $comp.
198 sub compression_get_file_extension
{
201 error
(g_
('%s is not a supported compression'), $comp)
202 unless compression_is_supported
($comp);
204 return $COMP{$comp}{file_ext
};
207 =item $comp = compression_get_default()
209 Return the default compression method. It is "xz" unless
210 C<compression_set_default> has been used to change it.
214 sub compression_get_default
{
215 return $default_compression;
218 =item compression_set_default($comp)
220 Change the default compression method. Errors out if the
221 given compression method is not supported.
225 sub compression_set_default
{
227 error
(g_
('%s is not a supported compression'), $method)
228 unless compression_is_supported
($method);
229 $default_compression = $method;
232 =item $level = compression_get_default_level()
234 Return the global default compression level used when compressing data if
235 it has been set, otherwise the default level for the default compressor.
237 It's "9" for "gzip" and "bzip2", "6" for "xz" and "lzma", unless
238 C<compression_set_default_level> has been used to change it.
242 sub compression_get_default_level
{
243 if (defined $default_compression_level) {
244 return $default_compression_level;
246 return $COMP{$default_compression}{default_level
};
250 =item compression_set_default_level($level)
252 Change the global default compression level. Passing undef as the level will
253 reset it to the global default compressor specific default, otherwise errors
254 out if the level is not valid (see C<compression_is_valid_level>).
258 sub compression_set_default_level
{
260 error
(g_
('%s is not a compression level'), $level)
261 if defined($level) and not compression_is_valid_level
($level);
262 $default_compression_level = $level;
265 =item $level = compression_get_level($comp)
267 Return the compression level used when compressing data with a specific
268 compressor. The value returned is the specific compression level if it has
269 been set, otherwise the global default compression level if it has been set,
270 falling back to the specific default compression level.
274 sub compression_get_level
{
277 error
(g_
('%s is not a supported compression'), $comp)
278 unless compression_is_supported
($comp);
280 return $COMP{$comp}{level
} //
281 $default_compression_level //
282 $COMP{$comp}{default_level
};
285 =item compression_set_level($comp, $level)
287 Change the compression level for a specific compressor. Passing undef as
288 the level will reset it to the specific default compressor level, otherwise
289 errors out if the level is not valid (see C<compression_is_valid_level>).
293 sub compression_set_level
{
294 my ($comp, $level) = @_;
296 error
(g_
('%s is not a supported compression'), $comp)
297 unless compression_is_supported
($comp);
298 error
(g_
('%s is not a compression level'), $level)
299 if defined $level && ! compression_is_valid_level
($level);
301 $COMP{$comp}{level
} = $level;
304 =item compression_is_valid_level($level)
306 Returns a boolean indicating whether $level is a valid compression level
307 (it must be either a number between 1 and 9 or "fast" or "best")
311 sub compression_is_valid_level
{
313 return $level =~ /^([1-9]|fast|best)$/;
316 =item $threads = compression_get_threads()
318 Return the number of threads to use for compression and decompression.
322 sub compression_get_threads
{
323 return $default_compression_threads;
326 =item compression_set_threads($threads)
328 Change the threads to use for compression and decompression. Passing C<undef>
329 or B<0> requests to use automatic mode, based on the current CPU cores on
334 sub compression_set_threads
{
337 error
(g_
('compression threads %s is not a number'), $threads)
338 if defined $threads && $threads !~ m/^\d+$/;
339 $default_compression_threads = $threads;
342 =item @exec = compression_get_cmdline_compress($comp)
344 Returns a list ready to be passed to C<exec>, its first element is the
345 program name for compression and the following elements are parameters
348 When executed the program will act as a filter between its standard input
349 and its standard output.
353 sub compression_get_cmdline_compress
{
356 error
(g_
('%s is not a supported compression'), $comp)
357 unless compression_is_supported
($comp);
359 my @prog = @
{$COMP{$comp}{comp_prog
}};
360 my $level = compression_get_level
($comp);
361 if ($level =~ m/^[1-9]$/) {
362 push @prog, "-$level";
364 push @prog, "--$level";
366 my $threads = compression_get_threads
();
368 # Do not generate warnings when adjusting memory usage, nor
369 # exit with non-zero due to those not emitted warnings.
370 push @prog, qw(--quiet --no-warn);
372 # Do not let xz fallback to single-threaded mode, to avoid
373 # non-reproducible output.
374 push @prog, '--no-adjust';
376 # The xz -T1 option selects a single-threaded mode which generates
377 # different output than in multi-threaded mode. To avoid the
378 # non-reproducible output we pass -T+1 (supported with xz >= 5.4.0)
379 # to request multi-threaded mode with a single thread.
380 push @prog, $threads == 1 ?
'-T+1' : "-T$threads";
385 =item @exec = compression_get_cmdline_decompress($comp)
387 Returns a list ready to be passed to C<exec>, its first element is the
388 program name for decompression and the following elements are parameters
391 When executed the program will act as a filter between its standard input
392 and its standard output.
396 sub compression_get_cmdline_decompress
{
399 error
(g_
('%s is not a supported compression'), $comp)
400 unless compression_is_supported
($comp);
402 my @prog = @
{$COMP{$comp}{decomp_prog
}};
404 my $threads = compression_get_threads
();
406 push @prog, "-T$threads";
416 =head2 Version 2.01 (dpkg 1.21.14)
418 New functions: compression_get_file_extension(), compression_get_level(),
419 compression_set_level(), compression_get_cmdline_compress(),
420 compression_get_cmdline_decompress(), compression_get_threads() and
421 compression_set_threads().
423 Deprecated functions: compression_get_property().
425 =head2 Version 2.00 (dpkg 1.20.0)
427 Hide variables: $default_compression, $default_compression_level
428 and $compression_re_file_ext.
430 =head2 Version 1.02 (dpkg 1.17.2)
432 New function: compression_get_file_extension_regex()
434 Deprecated variables: $default_compression, $default_compression_level
435 and $compression_re_file_ext
437 =head2 Version 1.01 (dpkg 1.16.1)
439 Default compression level is not global any more, it is per compressor type.
441 =head2 Version 1.00 (dpkg 1.15.6)
443 Mark the module as public.