/[soft]/rpm/urpmi/branches/2/urpm.pm
ViewVC logotype

Contents of /rpm/urpmi/branches/2/urpm.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2778 - (show annotations) (download)
Mon Jan 23 20:14:33 2012 UTC (12 years, 3 months ago) by tv
Original Path: rpm/urpmi/trunk/urpm.pm
File size: 14731 byte(s)
(ui_msg) kill it, obsolete for years, thus fixing a GC cycle
1 package urpm;
2
3 # $Id: urpm.pm 271301 2010-11-22 00:50:49Z eugeni $
4
5 no warnings 'utf8';
6 use strict;
7 use File::Find ();
8 use urpm::msg;
9 use urpm::download;
10 use urpm::util;
11 use urpm::sys;
12 use urpm::cfg;
13 use urpm::md5sum;
14
15 our $VERSION = '6.43';
16 our @ISA = qw(URPM Exporter);
17 our @EXPORT_OK = ('file_from_local_url', 'file_from_local_medium', 'is_local_medium');
18
19 use URPM;
20 use URPM::Resolve;
21
22 #- this violently overrides is_arch_compat() to always return true.
23 sub shunt_ignorearch {
24 eval q( sub URPM::Package::is_arch_compat { 1 } );
25 }
26
27 sub xml_info_policies() { qw(never on-demand update-only always) }
28
29 sub default_options {
30 {
31 'split-level' => 1,
32 'split-length' => 8,
33 'verify-rpm' => 1,
34 'post-clean' => 1,
35 'xml-info' => 'on-demand',
36 'max-round-robin-tries' => 5,
37 'max-round-robin-probes' => 2,
38 'days-between-mirrorlist-update' => 5,
39 'nb-of-new-unrequested-pkgs-between-auto-select-orphans-check' => 10,
40 };
41 }
42
43 #- create a new urpm object.
44 sub new {
45 my ($class) = @_;
46 my $self;
47 $self = bless {
48 # from URPM
49 depslist => [],
50 provides => {},
51 obsoletes => {},
52
53 media => undef,
54 options => {},
55
56 fatal => sub { printf STDERR "%s\n", $_[1]; exit($_[0]) },
57 error => sub { printf STDERR "%s\n", $_[0] },
58 info => sub { printf "%s\n", $_[0] }, #- displayed unless --quiet
59 log => sub { printf "%s\n", $_[0] }, #- displayed if --verbose
60 print => sub { printf "%s\n", $_[0] }, #- always displayed, enable to redirect output for eg: installer
61 }, $class;
62
63 set_files($self, '');
64 $self->set_nofatal(1);
65 $self;
66 }
67
68 sub new_parse_cmdline {
69 my ($class) = @_;
70 my $urpm = $class->new;
71 urpm::args::parse_cmdline(urpm => $urpm);
72 get_global_options($urpm);
73 $urpm;
74 }
75
76 sub _add2hash { my ($a, $b) = @_; while (my ($k, $v) = each %{$b || {}}) { defined $a->{$k} or $a->{$k} = $v } $a }
77
78 sub get_global_options {
79 my ($urpm) = @_;
80
81 my $config = urpm::cfg::load_config($urpm->{config})
82 or $urpm->{fatal}(6, $urpm::cfg::err);
83
84 if (my $global = $config->{global}) {
85 _add2hash($urpm->{options}, $global);
86 }
87 #- remember global options for write_config
88 $urpm->{global_config} = $config->{global};
89
90 _add2hash($urpm->{options}, default_options());
91 }
92
93 sub prefer_rooted {
94 my ($root, $file) = @_;
95 -e "$root$file" ? "$root$file" : $file;
96 }
97
98 sub init_cache_dir {
99 my ($urpm, $dir) = @_;
100
101 mkdir $dir, 0755; # try to create it
102
103 -d $dir && ! -l $dir or $urpm->{fatal}(1, N("fail to create directory %s", $dir));
104 -o $dir && -w $dir or $urpm->{fatal}(1, N("invalid owner for directory %s", $dir));
105
106 mkdir "$dir/partial";
107 mkdir "$dir/rpms";
108
109 $dir;
110 }
111 sub userdir_prefix {
112 my ($_urpm) = @_;
113 '/tmp/.urpmi-';
114 }
115 sub userdir {
116 #mdkonline uses userdir because it runs as user
117 my ($urpm) = @_;
118 $< or return;
119
120 my $dir = ($urpm->{urpmi_root} || '') . userdir_prefix($urpm) . $<;
121 init_cache_dir($urpm, $dir);
122 }
123 sub ensure_valid_cachedir {
124 my ($urpm) = @_;
125 if (my $dir = userdir($urpm)) {
126 $urpm->{cachedir} = $dir;
127 }
128 -w "$urpm->{cachedir}/partial" or $urpm->{fatal}(1, N("Can not download packages into %s", "$urpm->{cachedir}/partial"));
129 }
130 sub valid_cachedir {
131 my ($urpm) = @_;
132 userdir($urpm) || $urpm->{cachedir};
133 }
134
135 sub is_temporary_file {
136 my ($urpm, $f) = @_;
137
138 begins_with($f, $urpm->{cachedir});
139 }
140
141 sub set_env {
142 my ($urpm, $env) = @_;
143 -d $env or $urpm->{fatal}(8, N("Environment directory %s does not exist", $env));
144 print N("using specific environment on %s\n", $env);
145 #- setting new environment.
146 $urpm->{config} = "$env/urpmi.cfg";
147 if (cat_($urpm->{config}) =~ /^\s*virtual\s*$/m) {
148 print "dropping virtual from $urpm->{config}\n";
149 system(q(perl -pi -e 's/^\s*virtual\s*$//' ) . $urpm->{config});
150 }
151 $urpm->{mediacfgdir} = "$env/mediacfg.d";
152 $urpm->{skiplist} = "$env/skip.list";
153 $urpm->{instlist} = "$env/inst.list";
154 $urpm->{prefer_list} = "$env/prefer.list";
155 $urpm->{prefer_vendor_list} = "$env/prefer.vendor.list";
156 $urpm->{statedir} = $env;
157 $urpm->{env_rpmdb} = "$env/rpmdb.cz";
158 $urpm->{env_dir} = $env;
159 }
160
161 sub set_files {
162 my ($urpm, $urpmi_root) = @_;
163
164 $urpmi_root and $urpmi_root = file2absolute_file($urpmi_root);
165
166 my %h = (
167 config => "$urpmi_root/etc/urpmi/urpmi.cfg",
168 mediacfgdir => "$urpmi_root/etc/urpmi/mediacfg.d",
169 skiplist => prefer_rooted($urpmi_root, '/etc/urpmi/skip.list'),
170 instlist => prefer_rooted($urpmi_root, '/etc/urpmi/inst.list'),
171 prefer_list => prefer_rooted($urpmi_root, '/etc/urpmi/prefer.list'),
172 prefer_vendor_list =>
173 prefer_rooted($urpmi_root, '/etc/urpmi/prefer.vendor.list'),
174 private_netrc => "$urpmi_root/etc/urpmi/netrc",
175 statedir => "$urpmi_root/var/lib/urpmi",
176 cachedir => "$urpmi_root/var/cache/urpmi",
177 root => $urpmi_root,
178 $urpmi_root ? (urpmi_root => $urpmi_root) : (),
179 );
180 $urpm->{$_} = $h{$_} foreach keys %h;
181
182 create_var_lib_rpm($urpm, %h);
183
184 # policy is too use chroot environment only for --urpmi-root, not for --root:
185 if ($urpmi_root && -e "$urpmi_root/etc/rpm/macros") {
186 URPM::loadmacrosfile("$urpmi_root/etc/rpm/macros");
187 }
188 }
189
190 sub create_var_lib_rpm {
191 my ($urpm, %h) = @_;
192 require File::Path;
193 File::Path::mkpath([ $h{statedir},
194 (map { "$h{cachedir}/$_" } qw(partial rpms)),
195 dirname($h{config}),
196 "$urpm->{root}/var/lib/rpm",
197 "$urpm->{root}/var/tmp",
198 ]);
199 }
200
201 sub modify_rpm_macro {
202 my ($name, $to_remove, $to_add) = @_;
203
204 my $val = URPM::expand('%' . $name);
205 $val =~ s/$to_remove/$to_add/ or $val = join(' ', grep { $_ } $val, $to_add);
206 URPM::add_macro("$name $val");
207 }
208
209 sub set_tune_rpm {
210 my ($urpm, $para) = @_;
211
212 my %h = map { $_ => 1 } map {
213 if ($_ eq 'all') {
214 ('nofsync', 'private');
215 } else {
216 $_;
217 }
218 } split(',', $para);
219
220 $urpm->{tune_rpm} = \%h;
221 }
222
223 sub tune_rpm {
224 my ($urpm) = @_;
225
226 if ($urpm->{tune_rpm}{nofsync}) {
227 modify_rpm_macro('__dbi_other', 'fsync', 'nofsync');
228 }
229 if ($urpm->{tune_rpm}{private}) {
230 urpm::sys::clean_rpmdb_shared_regions($urpm->{root});
231 modify_rpm_macro('__dbi_other', 'usedbenv', 'private');
232 }
233 }
234
235 sub _blist_pkg_to_urls {
236 my ($blist, @pkgs) = @_;
237 my $base_url = $blist->{medium}{url} . '/';
238 map { $base_url . $_->filename } @pkgs;
239 }
240 sub blist_pkg_to_url {
241 my ($blist, $pkg) = @_;
242 my ($url) = _blist_pkg_to_urls($blist, $pkg);
243 $url;
244 }
245 sub blist_to_urls {
246 my ($blist) = @_;
247 _blist_pkg_to_urls($blist, values %{$blist->{pkgs}});
248 }
249 sub blist_to_filenames {
250 my ($blist) = @_;
251 map { $_->filename } values %{$blist->{pkgs}};
252 }
253
254 sub protocol_from_url {
255 my ($url) = @_;
256 $url =~ m!^(\w+)(_[^:]*)?:! && $1;
257 }
258 sub file_from_local_url {
259 my ($url) = @_;
260 $url =~ m!^(?:removable[^:]*:/|file:/)?(/.*)! && $1;
261 }
262 sub file_from_local_medium {
263 my ($medium, $o_url) = @_;
264 my $url = $o_url || $medium->{url};
265 if ($url =~ m!^cdrom://(.*)!) {
266 my $rel = $1;
267 $medium->{mntpoint} or do { require Carp; Carp::confess("cdrom is not mounted yet!\n") };
268 "$medium->{mntpoint}/$rel";
269 } else {
270 file_from_local_url($url);
271 }
272 }
273 sub is_local_url {
274 my ($url) = @_;
275 file_from_local_url($url) || is_cdrom_url($url);
276 }
277 sub is_local_medium {
278 my ($medium) = @_;
279 is_local_url($medium->{url});
280 }
281 sub is_cdrom_url {
282 my ($url) = @_;
283 protocol_from_url($url) eq 'cdrom';
284 }
285
286 sub db_open_or_die_ {
287 my ($urpm, $b_write_perm) = @_;
288 my $db;
289 if ($urpm->{env_rpmdb}) {
290 #- URPM has same methods as URPM::DB and empty URPM will be seen as empty URPM::DB.
291 $db = new URPM;
292 $db->parse_synthesis($urpm->{env_rpmdb});
293 } else {
294 $db = db_open_or_die($urpm, $urpm->{root}, $b_write_perm);
295 }
296 $db;
297 }
298
299 # please use higher level function db_open_or_die_()
300 sub db_open_or_die {
301 my ($urpm, $root, $b_write_perm) = @_;
302
303 $urpm->{debug} and $urpm->{debug}("opening rpmdb (root=$root, write=$b_write_perm)");
304
305 my $db = URPM::DB::open($root, $b_write_perm || 0)
306 or $urpm->{fatal}(9, N("unable to open rpmdb"));
307
308 $db;
309 }
310
311 #- register local packages for being installed, keep track of source.
312 sub register_rpms {
313 my ($urpm, @files) = @_;
314 my ($start, $id, $error, %requested);
315
316 #- examine each rpm and build the depslist for them using current
317 #- depslist and provides environment.
318 $start = @{$urpm->{depslist}};
319 foreach (@files) {
320 /\.(?:rpm|spec)$/ or $error = 1, $urpm->{error}(N("invalid rpm file name [%s]", $_)), next;
321
322 #- if that's an URL, download.
323 if (protocol_from_url($_)) {
324 my $basename = basename($_);
325 unlink "$urpm->{cachedir}/partial/$basename";
326 $urpm->{log}(N("retrieving rpm file [%s] ...", $_));
327 if (urpm::download::sync_url($urpm, $_, quiet => 1)) {
328 $urpm->{log}(N("...retrieving done"));
329 $_ = "$urpm->{cachedir}/partial/$basename";
330 } else {
331 $urpm->{error}(N("...retrieving failed: %s", $@));
332 unlink "$urpm->{cachedir}/partial/$basename";
333 next;
334 }
335 } else {
336 -r $_ or $error = 1, $urpm->{error}(N("unable to access rpm file [%s]", $_)), next;
337 }
338
339 if (/\.spec$/) {
340 my $pkg = URPM::spec2srcheader($_)
341 or $error = 1, $urpm->{error}(N("unable to parse spec file %s [%s]", $_, $!)), next;
342 $id = @{$urpm->{depslist}};
343 $urpm->{depslist}[$id] = $pkg;
344 $pkg->set_id($id); #- sets internal id to the depslist id.
345 $urpm->{source}{$id} = $_;
346 } else {
347 ($id) = $urpm->parse_rpm($_);
348 my $pkg = defined $id && $urpm->{depslist}[$id];
349 $pkg or $error = 1, $urpm->{error}(N("unable to register rpm file")), next;
350 $pkg->arch eq 'src' || $pkg->is_arch_compat
351 or $error = 1, $urpm->{error}(N("Incompatible architecture for rpm [%s]", $_)), next;
352 $urpm->{source}{$id} = $_;
353 }
354 }
355 $error and $urpm->{fatal}(2, N("error registering local packages"));
356 defined $id && $start <= $id and @requested{($start .. $id)} = (1) x ($id-$start+1);
357
358 #- distribute local packages to distant nodes directly in cache of each machine.
359 if (@files && $urpm->{parallel_handler}) {
360 $urpm->{parallel_handler}->parallel_register_rpms($urpm, @files);
361 }
362
363 %requested;
364 }
365
366 #- checks whether the delta RPM represented by $pkg is installable wrt the
367 #- RPM DB on $root. For this, it extracts the rpm version to which the
368 #- delta applies from the delta rpm filename itself. So naming conventions
369 #- do matter :)
370 sub is_delta_installable {
371 my ($urpm, $pkg, $root) = @_;
372 $pkg->flag_installed or return 0;
373 my $f = $pkg->filename;
374 my $n = $pkg->name;
375 my ($v_match) = $f =~ /^\Q$n\E-(.*)_.+\.delta\.rpm$/;
376 my $db = db_open_or_die($urpm, $root);
377 my $v_installed;
378 $db->traverse(sub {
379 my ($p) = @_;
380 $p->name eq $n and $v_installed = $p->version . '-' . $p->release;
381 });
382 $v_match eq $v_installed;
383 }
384
385 #- extract package that should be installed instead of upgraded,
386 #- installing instead of upgrading is useful
387 #- - for inst.list (cf flag disable_obsolete)
388 #- sources is a hash of id -> source rpm filename.
389 sub extract_packages_to_install {
390 my ($urpm, $sources, $_state) = @_;
391 my %inst;
392
393 foreach (keys %$sources) {
394 my $pkg = $urpm->{depslist}[$_] or next;
395 $pkg->flag_disable_obsolete
396 and $inst{$pkg->id} = delete $sources->{$pkg->id};
397 }
398
399 \%inst;
400 }
401
402 #- deprecated
403 sub install { require urpm::install; &urpm::install::install }
404
405 #- deprecated
406 sub parallel_remove { &urpm::parallel::remove }
407
408 #- get reason of update for packages to be updated
409 #- use all update medias if none given
410 sub get_updates_description {
411 my ($urpm, @update_medias) = @_;
412 my %update_descr;
413 my ($cur, $section);
414
415 @update_medias or @update_medias = urpm::media::non_ignored_media($urpm, 'update');
416
417 foreach my $medium (@update_medias) {
418 # fix not taking into account the last %package token of each descrptions file: '%package dummy'
419 foreach (cat_utf8(urpm::media::statedir_descriptions($urpm, $medium)),
420 ($::env ? cat_utf8("$::env/descriptions") : ()), '%package dummy') {
421 /^%package +(.+)/ and do {
422 # fixes not parsing descriptions file when MU adds itself the security source:
423 if (exists $cur->{importance} && !member($cur->{importance}, qw(security bugfix))) {
424 $cur->{importance} = 'normal';
425 }
426 $update_descr{$medium->{name}}{$_} = $cur foreach @{$cur->{pkgs} || []};
427 $cur = { pkgs => [ split /\s/, $1 ] };
428 $section = 'pkg';
429 next;
430 };
431 /^Updated?: +(.+)/ && $section eq 'pkg' and do { $cur->{updated} = $1; next };
432 /^Importance: +(.+)/ && $section eq 'pkg' and do { $cur->{importance} = $1; next };
433 /^(ID|URL): +(.+)/ && $section eq 'pkg' and do { $cur->{$1} = $2; next };
434 /^%(pre|description)/ and do { $section = $1; next };
435 $section =~ /^(pre|description)\z/ and $cur->{$1} .= $_;
436 }
437 }
438 \%update_descr;
439 }
440
441 sub error_restricted ($) {
442 my ($urpm) = @_;
443 $urpm->{fatal}(2, N("This operation is forbidden while running in restricted mode"));
444 }
445
446 sub DESTROY {}
447
448 1;
449
450 __END__
451
452 =head1 NAME
453
454 urpm - Mageia perl tools to handle the urpmi database
455
456 =head1 DESCRIPTION
457
458 C<urpm> is used by urpmi executables to manipulate packages and media
459 on a Mageia Linux distribution.
460
461 =head2 The urpm class
462
463 =over 4
464
465 =item urpm->new()
466
467 The constructor creates a new urpm object. It's a blessed hash that
468 contains fields from C<URPM>, and also the following fields:
469
470 B<source>: { id => src_rpm_file|spec_file }
471
472 B<media>: [ {
473 start => int, end => int, name => string, url => string,
474 virtual => bool, media_info_dir => string, with_synthesis => string,
475 no-media-info => bool,
476 iso => string, downloader => string,
477 ignore => bool, update => bool, modified => bool, really_modified => bool,
478 unknown_media_info => bool,
479 } ],
480
481 =back
482
483 =head1 SEE ALSO
484
485 The C<URPM> package is used to manipulate at a lower level synthesis and rpm
486 files.
487
488 =head1 COPYRIGHT
489
490 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA
491
492 Copyright (C) 2005-2010 Mandriva SA
493
494 This program is free software; you can redistribute it and/or modify
495 it under the terms of the GNU General Public License as published by
496 the Free Software Foundation; either version 2, or (at your option)
497 any later version.
498
499 This program is distributed in the hope that it will be useful,
500 but WITHOUT ANY WARRANTY; without even the implied warranty of
501 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
502 GNU General Public License for more details.
503
504 You should have received a copy of the GNU General Public License
505 along with this program; if not, write to the Free Software
506 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
507
508 =cut
509
510 # ex: set ts=8 sts=4 sw=4 noet:

  ViewVC Help
Powered by ViewVC 1.1.30