File Coverage

blib/lib/urpm/cfg.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package urpm::cfg;
2              
3              
4 7     7   1289012 use strict;
  7         20  
  7         231  
5 7     7   43 use warnings;
  7         17  
  7         292  
6 7     7   1360 use urpm::util qw(any cat_ partition output_safe quotespace unquotespace);
  7         24  
  7         655  
7 7     7   1649 use urpm::msg 'N';
  0            
  0            
8              
9             =head1 NAME
10              
11             urpm::cfg - routines to handle the urpmi configuration files
12              
13             =head1 SYNOPSIS
14              
15             =head1 DESCRIPTION
16              
17             =over
18              
19             =item load_config($file)
20              
21             Reads an urpmi configuration file and returns its contents in a hash ref :
22              
23             {
24             media => [
25             {
26             name => 'medium name 1',
27             url => 'http://...',
28             option => 'value',
29             ...
30             },
31             ],
32             global => {
33             # global options go here
34             },
35             }
36              
37             Returns undef() in case of parsing error (and sets C<$urpm::cfg::err> to the
38             appropriate error message.)
39              
40             =item dump_config($file, $config)
41              
42             Does the opposite: write the configuration file, from the same data structure.
43             Returns 1 on success, 0 on failure.
44              
45             =cut
46              
47             #- implementations of the substitutions. arch and release are mdk-specific.
48             #- XXX this is fragile code, it's an heuristic that depends on the format of
49             #- /etc/release
50              
51             my ($arch, $release);
52             sub _init_arch_release () {
53             if (!$arch && !$release) {
54             my $l = cat_('/etc/release') or return undef;
55             ($release, $arch) = $l =~ /release (\d+\.?\d?).*for (\w+)/;
56             $release = 'cauldron' if $l =~ /cauldron/i;
57             }
58             1;
59             }
60              
61             sub get_arch () { _init_arch_release(); $arch }
62              
63             sub get_release () { _init_arch_release(); $release }
64              
65             sub get_host () {
66             my $h = cat_('/proc/sys/kernel/hostname') || $ENV{HOSTNAME} || `/bin/hostname`;
67             chomp $h;
68             $h;
69             }
70              
71             our $err;
72              
73             sub _syntax_error () { $err = N("syntax error in config file at line %s", $.) }
74              
75             sub substitute_back {
76             my ($new, $old) = @_;
77             return $new if !defined($old);
78             return $old if expand_line($old) eq $new;
79             return $new;
80             }
81              
82             my %substitutions;
83             sub expand_line {
84             my ($line) = @_;
85             unless (scalar keys %substitutions) {
86             %substitutions = (
87             HOST => get_host(),
88             ARCH => get_arch(),
89             RELEASE => get_release(),
90             );
91             }
92             foreach my $sub (keys %substitutions) {
93             $line =~ s/\$$sub\b/$substitutions{$sub}/g;
94             }
95             return $line;
96             }
97              
98             my $no_para_option_regexp = 'update|ignore|synthesis|noreconfigure|no-recommends|no-suggests|no-media-info|static|virtual|disable-certificate-check';
99              
100             sub load_config_raw {
101             my ($file, $b_norewrite) = @_;
102             my @blocks;
103             my $block;
104             $err = '';
105             -r $file or do {
106             $err = N("unable to read config file [%s]", $file);
107             return;
108             };
109             foreach (cat_($file)) {
110             chomp;
111             next if /^\s*#/; #- comments
112             s/^\s+//; s/\s+$//;
113             $_ = expand_line($_) unless $b_norewrite;
114             if ($_ eq '}') { #-{
115             if (!defined $block) {
116             _syntax_error();
117             return;
118             }
119             push @blocks, $block;
120             undef $block;
121             } elsif (defined $block && /{$/) { #-}
122             _syntax_error();
123             return;
124             } elsif ($_ eq '{') {
125             #-} Entering a global block
126             $block = { name => '' };
127             } elsif (/^(.*?[^\\])\s+(?:(.*?[^\\])\s+)?{$/) {
128             #- medium definition
129             my ($name, $url) = (unquotespace($1), unquotespace($2));
130             if (any { $_->{name} eq $name } @blocks) {
131             #- hmm, somebody fudged urpmi.cfg by hand.
132             $err = N("medium `%s' is defined twice, aborting", $name);
133             return;
134             }
135             $block = { name => $name, $url ? (url => $url) : @{[]} };
136             } elsif (/^(hdlist
137             |list
138             |with_hdlist
139             |with_synthesis
140             |with-dir
141             |mirrorlist
142             |media_info_dir
143             |removable
144             |md5sum
145             |limit-rate
146             |nb-of-new-unrequested-pkgs-between-auto-select-orphans-check
147             |xml-info
148             |excludepath
149             |split-(?:level|length)
150             |priority-upgrade
151             |prohibit-remove
152             |downloader
153             |retry
154             |default-media
155             |download-all
156             |tune-rpm
157             |(?:curl|rsync|wget|prozilla|aria2)-options
158             )\s*:\s*['"]?(.*?)['"]?$/x) {
159             #- config values
160             $block->{$1} = $2;
161             } elsif (/^key[-_]ids\s*:\s*['"]?(.*?)['"]?$/) {
162             $block->{'key-ids'} = $1;
163             } elsif (/^(hdlist|synthesis)$/) {
164             # ignored, kept for compatibility
165             } elsif (/^($no_para_option_regexp)$/) {
166             my $opt = $1;
167             if ($opt =~ s/no-suggests/no-recommends/) { # COMPAT
168             warn "WARNING: --no-suggests is deprecated. Use --no-recommends instead\n" if s/no-suggests/no-recommends/; # COMPAT
169             }
170             #- positive flags
171             $block->{$opt} = 1;
172             } elsif (my ($no, $k, $v) =
173             /^(no-)?(
174             verify-rpm
175             |norebuild
176             |fuzzy
177             |allow-(?:force|nodeps)
178             |(?:pre|post)-clean
179             |excludedocs
180             |compress
181             |keep
182             |ignoresize
183             |auto
184             |strict-arch
185             |nopubkey
186             |resume)(?:\s*:\s*(.*))?$/x
187             ) {
188             #- boolean options
189             my $yes = $no ? 0 : 1;
190             $no = $yes ? 0 : 1;
191             $v = '' unless defined $v;
192             $block->{$k} = $v =~ /^(yes|on|1|)$/i ? $yes : $no;
193             } elsif ($_ eq 'modified') {
194             #- obsolete
195             } else {
196             warn "unknown line '$_'\n" if $_;
197             }
198             }
199             \@blocks;
200             }
201              
202             sub load_config {
203             my ($file) = @_;
204              
205             my $blocks = load_config_raw($file);
206             my ($media, $global) = partition { $_->{name} } @$blocks;
207             ($global) = @$global;
208             delete $global->{name};
209              
210             { global => $global || {}, media => $media };
211             }
212              
213             sub dump_config {
214             my ($file, $config) = @_;
215              
216             my %global = (name => '', %{$config->{global}});
217              
218             dump_config_raw($file, [ %global ? \%global : @{[]}, @{$config->{media}} ]);
219             }
220              
221             sub dump_config_raw {
222             my ($file, $blocks) = @_;
223              
224             my $old_blocks = load_config_raw($file, 1);
225             my $substitute_back = sub {
226             my ($m, $field) = @_;
227             my ($prev_block) = grep { $_->{name} eq $m->{name} } @$old_blocks;
228             substitute_back($m->{$field}, $prev_block && $prev_block->{$field});
229             };
230              
231             my @lines;
232             foreach my $m (@$blocks) {
233             my @l = map {
234             if (/^($no_para_option_regexp)$/) {
235             $_;
236             } elsif ($_ ne 'priority') {
237             "$_: " . $substitute_back->($m, $_);
238             }
239             } sort grep { $_ && $_ ne 'url' && $_ ne 'name' } keys %$m;
240              
241             my $name_url = $m->{name} ?
242             join(' ', map { quotespace($_) } $m->{name}, $substitute_back->($m, 'url')) . ' ' : '';
243              
244             push @lines, join("\n", $name_url . '{', (map { " $_" } @l), "}\n");
245             }
246              
247             output_safe($file, join("\n", @lines)) or do {
248             $err = N("unable to write config file [%s]", $file);
249             return 0;
250             };
251              
252             1;
253             }
254              
255             1;
256              
257              
258             =back
259              
260             =head1 COPYRIGHT
261              
262             Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA
263              
264             Copyright (C) 2005-2010 Mandriva SA
265              
266             Copyright (C) 2011-2017 Mageia
267              
268             =cut