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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.30