diff options
99 files changed, 1672 insertions, 18 deletions
@@ -321,6 +321,7 @@ urpm/md5sum.pm urpm/media.pm urpm/mirrors.pm urpm/msg.pm +urpm/orphans.pm urpm/parallel.pm urpm/parallel_ka_run.pm urpm/parallel_ssh.pm @@ -1,4 +1,5 @@ - all tools: + o handle "unrequested orphans" (similar to "deborphan") o statedir files are now in /var/lib/urpmi/<medium-name>/ for eg: /var/lib/urpmi/synthesis.hdlist.<medium-name> is now /var/lib/urpmi/<medium-name>/synthesis.hdlist.cz diff --git a/pod/urpme.8.pod b/pod/urpme.8.pod index 77d441c2..27cb5468 100644 --- a/pod/urpme.8.pod +++ b/pod/urpme.8.pod @@ -5,6 +5,7 @@ urpme - rpm deinstaller =head1 SYNOPSIS urpme [options] [package_name...] + urpme [options] --auto-orphans =head1 DESCRIPTION @@ -37,6 +38,10 @@ This is the same as B<--verbose>. Removes packages non-interactively, without asking questions. +=item B<--auto-orphans> + +Removes orphans. + =item B<--test> Test deinstallation of packages but do not modify the system. diff --git a/pod/urpmi.8.pod b/pod/urpmi.8.pod index 408f7001..b80b81a5 100644 --- a/pod/urpmi.8.pod +++ b/pod/urpmi.8.pod @@ -107,6 +107,10 @@ Like B<--auto-select>, but also updates all relevant media before selection of upgradeable packages is made. This avoids a previous call to C<urpmi.update>. +=item B<--auto-orphans> + +Remove all orphans without asking (see also C<urpme --auto-orphans>) + =item B<--no-md5sum> Disable MD5SUM file checking when updating media. diff --git a/pod/urpmi.files.5.pod b/pod/urpmi.files.5.pod index 45baf3ba..26512a23 100644 --- a/pod/urpmi.files.5.pod +++ b/pod/urpmi.files.5.pod @@ -72,6 +72,13 @@ This file is handled by urpmi: when adding a media from an URL containing a password, urpmi will remove the password from the URL written into urpmi.cfg and write it in this file. +=item I<< /var/lib/urpmi/installed-through-deps.list >> + +Contains the name of the packages that were selected indirectly, ie not requested by user +(eg: libxxxN). It is used to detect orphans (try C<urpme --auto-orphans> and see). + +The format of the file is: one package name per line, or optionally "xxx (required by ...)" + =back =head1 SEE ALSO diff --git a/pod/urpmq.8.pod b/pod/urpmq.8.pod index fd266802..959044cc 100644 --- a/pod/urpmq.8.pod +++ b/pod/urpmq.8.pod @@ -84,6 +84,10 @@ searching packages and resolving dependencies. Select all packages that can be upgraded, according to already installed packages and packages listed in various registered media. +=item B<--auto-orphans> + +List orphans. + =item B<--no-suggests> With this option, urpmq will not require "suggested" packages. diff --git a/t/01compile.t b/t/01compile.t index 03410fca..2b81d0c3 100644 --- a/t/01compile.t +++ b/t/01compile.t @@ -2,7 +2,7 @@ use strict; use warnings; -use Test::More tests => 25; +use Test::More tests => 26; for my $module (glob("urpm/*.pm")) { $module =~ s,/,::,g; diff --git a/t/data/SPECS/orphans-1/a.spec b/t/data/SPECS/orphans-1/a.spec new file mode 100644 index 00000000..f75c94d2 --- /dev/null +++ b/t/data/SPECS/orphans-1/a.spec @@ -0,0 +1,13 @@ +Summary: x +Name: a +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/b.spec b/t/data/SPECS/orphans-1/b.spec new file mode 100644 index 00000000..337a7807 --- /dev/null +++ b/t/data/SPECS/orphans-1/b.spec @@ -0,0 +1,13 @@ +Summary: x +Name: b +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/c.spec b/t/data/SPECS/orphans-1/c.spec new file mode 100644 index 00000000..4bb4a950 --- /dev/null +++ b/t/data/SPECS/orphans-1/c.spec @@ -0,0 +1,14 @@ +Summary: x +Name: c +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: cc +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/cc.spec b/t/data/SPECS/orphans-1/cc.spec new file mode 100644 index 00000000..ee8387c0 --- /dev/null +++ b/t/data/SPECS/orphans-1/cc.spec @@ -0,0 +1,13 @@ +Summary: x +Name: cc +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/d.spec b/t/data/SPECS/orphans-1/d.spec new file mode 100644 index 00000000..53983ffb --- /dev/null +++ b/t/data/SPECS/orphans-1/d.spec @@ -0,0 +1,14 @@ +Summary: x +Name: d +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: dd +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/dd.spec b/t/data/SPECS/orphans-1/dd.spec new file mode 100644 index 00000000..c89f2aeb --- /dev/null +++ b/t/data/SPECS/orphans-1/dd.spec @@ -0,0 +1,13 @@ +Summary: x +Name: dd +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/e.spec b/t/data/SPECS/orphans-1/e.spec new file mode 100644 index 00000000..b8178f7d --- /dev/null +++ b/t/data/SPECS/orphans-1/e.spec @@ -0,0 +1,14 @@ +Summary: x +Name: e +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: ee1 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/ee1.spec b/t/data/SPECS/orphans-1/ee1.spec new file mode 100644 index 00000000..889c0506 --- /dev/null +++ b/t/data/SPECS/orphans-1/ee1.spec @@ -0,0 +1,13 @@ +Summary: x +Name: ee1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/f.spec b/t/data/SPECS/orphans-1/f.spec new file mode 100644 index 00000000..75f073b3 --- /dev/null +++ b/t/data/SPECS/orphans-1/f.spec @@ -0,0 +1,14 @@ +Summary: x +Name: f +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: ff1 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/ff1.spec b/t/data/SPECS/orphans-1/ff1.spec new file mode 100644 index 00000000..a078af5f --- /dev/null +++ b/t/data/SPECS/orphans-1/ff1.spec @@ -0,0 +1,13 @@ +Summary: x +Name: ff1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/g.spec b/t/data/SPECS/orphans-1/g.spec new file mode 100644 index 00000000..a626432d --- /dev/null +++ b/t/data/SPECS/orphans-1/g.spec @@ -0,0 +1,14 @@ +Summary: x +Name: g +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: gg = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/gg.spec b/t/data/SPECS/orphans-1/gg.spec new file mode 100644 index 00000000..7531870c --- /dev/null +++ b/t/data/SPECS/orphans-1/gg.spec @@ -0,0 +1,13 @@ +Summary: x +Name: gg +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/h.spec b/t/data/SPECS/orphans-1/h.spec new file mode 100644 index 00000000..4f9b2682 --- /dev/null +++ b/t/data/SPECS/orphans-1/h.spec @@ -0,0 +1,14 @@ +Summary: x +Name: h +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Suggests: hh +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/hh.spec b/t/data/SPECS/orphans-1/hh.spec new file mode 100644 index 00000000..7467d74d --- /dev/null +++ b/t/data/SPECS/orphans-1/hh.spec @@ -0,0 +1,13 @@ +Summary: x +Name: hh +Version: 1 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/l.spec b/t/data/SPECS/orphans-1/l.spec new file mode 100644 index 00000000..b74f0fa8 --- /dev/null +++ b/t/data/SPECS/orphans-1/l.spec @@ -0,0 +1,14 @@ +Summary: x +Name: l +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: ll +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/ll.spec b/t/data/SPECS/orphans-1/ll.spec new file mode 100644 index 00000000..071650cc --- /dev/null +++ b/t/data/SPECS/orphans-1/ll.spec @@ -0,0 +1,14 @@ +Summary: x +Name: ll +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: l +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/m.spec b/t/data/SPECS/orphans-1/m.spec new file mode 100644 index 00000000..4074abe4 --- /dev/null +++ b/t/data/SPECS/orphans-1/m.spec @@ -0,0 +1,14 @@ +Summary: x +Name: m +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: mm = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/mm.spec b/t/data/SPECS/orphans-1/mm.spec new file mode 100644 index 00000000..3dc9d24e --- /dev/null +++ b/t/data/SPECS/orphans-1/mm.spec @@ -0,0 +1,14 @@ +Summary: x +Name: mm +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: m +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/n.spec b/t/data/SPECS/orphans-1/n.spec new file mode 100644 index 00000000..af7fb8a5 --- /dev/null +++ b/t/data/SPECS/orphans-1/n.spec @@ -0,0 +1,14 @@ +Summary: x +Name: n +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: nn = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/nn.spec b/t/data/SPECS/orphans-1/nn.spec new file mode 100644 index 00000000..e3c95c2b --- /dev/null +++ b/t/data/SPECS/orphans-1/nn.spec @@ -0,0 +1,14 @@ +Summary: x +Name: nn +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: n = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/o.spec b/t/data/SPECS/orphans-1/o.spec new file mode 100644 index 00000000..a85d038c --- /dev/null +++ b/t/data/SPECS/orphans-1/o.spec @@ -0,0 +1,14 @@ +Summary: x +Name: o +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: oo%version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/oo1.spec b/t/data/SPECS/orphans-1/oo1.spec new file mode 100644 index 00000000..319a05a4 --- /dev/null +++ b/t/data/SPECS/orphans-1/oo1.spec @@ -0,0 +1,14 @@ +Summary: x +Name: oo1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: o = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/r.spec b/t/data/SPECS/orphans-1/r.spec new file mode 100644 index 00000000..28feb112 --- /dev/null +++ b/t/data/SPECS/orphans-1/r.spec @@ -0,0 +1,14 @@ +Summary: x +Name: r +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: rr +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-a.spec b/t/data/SPECS/orphans-1/req-a.spec new file mode 100644 index 00000000..1939f59e --- /dev/null +++ b/t/data/SPECS/orphans-1/req-a.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-a +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: a +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-b.spec b/t/data/SPECS/orphans-1/req-b.spec new file mode 100644 index 00000000..1abe81b8 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-b.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-b +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: b +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-c.spec b/t/data/SPECS/orphans-1/req-c.spec new file mode 100644 index 00000000..9de29a7e --- /dev/null +++ b/t/data/SPECS/orphans-1/req-c.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-c +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: c +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-d.spec b/t/data/SPECS/orphans-1/req-d.spec new file mode 100644 index 00000000..e18c4e39 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-d.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-d +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: d +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-e.spec b/t/data/SPECS/orphans-1/req-e.spec new file mode 100644 index 00000000..eb279f06 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-e.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-e +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: e +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-f.spec b/t/data/SPECS/orphans-1/req-f.spec new file mode 100644 index 00000000..0c92520b --- /dev/null +++ b/t/data/SPECS/orphans-1/req-f.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-f +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: f +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-g.spec b/t/data/SPECS/orphans-1/req-g.spec new file mode 100644 index 00000000..8ead4246 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-g.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-g +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: g +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-h.spec b/t/data/SPECS/orphans-1/req-h.spec new file mode 100644 index 00000000..5af41ab0 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-h.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-h +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: h +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-l.spec b/t/data/SPECS/orphans-1/req-l.spec new file mode 100644 index 00000000..e5acbee7 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-l.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-l +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: l +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-m.spec b/t/data/SPECS/orphans-1/req-m.spec new file mode 100644 index 00000000..3e225a18 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-m.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-m +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: m +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-n.spec b/t/data/SPECS/orphans-1/req-n.spec new file mode 100644 index 00000000..8e6473bc --- /dev/null +++ b/t/data/SPECS/orphans-1/req-n.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-n +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: n +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-o.spec b/t/data/SPECS/orphans-1/req-o.spec new file mode 100644 index 00000000..beb04be2 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-o.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-o +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: o +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-r.spec b/t/data/SPECS/orphans-1/req-r.spec new file mode 100644 index 00000000..d05bae88 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-r.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-r +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: r +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-s.spec b/t/data/SPECS/orphans-1/req-s.spec new file mode 100644 index 00000000..e85a3c35 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-s.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-s +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: s +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/req-t.spec b/t/data/SPECS/orphans-1/req-t.spec new file mode 100644 index 00000000..70b8ce17 --- /dev/null +++ b/t/data/SPECS/orphans-1/req-t.spec @@ -0,0 +1,14 @@ +Summary: x +Name: req-t +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: t +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/rr1.spec b/t/data/SPECS/orphans-1/rr1.spec new file mode 100644 index 00000000..f89b79b0 --- /dev/null +++ b/t/data/SPECS/orphans-1/rr1.spec @@ -0,0 +1,14 @@ +Summary: x +Name: rr1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Provides: rr +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/rr2.spec b/t/data/SPECS/orphans-1/rr2.spec new file mode 100644 index 00000000..a2cf3057 --- /dev/null +++ b/t/data/SPECS/orphans-1/rr2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: rr2 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Provides: rr +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/s.spec b/t/data/SPECS/orphans-1/s.spec new file mode 100644 index 00000000..da80e9db --- /dev/null +++ b/t/data/SPECS/orphans-1/s.spec @@ -0,0 +1,14 @@ +Summary: x +Name: s +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: ss1 ss2 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/ss1.spec b/t/data/SPECS/orphans-1/ss1.spec new file mode 100644 index 00000000..434dc73a --- /dev/null +++ b/t/data/SPECS/orphans-1/ss1.spec @@ -0,0 +1,14 @@ +Summary: x +Name: ss1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Provides: ss +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/ss2.spec b/t/data/SPECS/orphans-1/ss2.spec new file mode 100644 index 00000000..a7a14f4e --- /dev/null +++ b/t/data/SPECS/orphans-1/ss2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: ss2 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Provides: ss +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/t.spec b/t/data/SPECS/orphans-1/t.spec new file mode 100644 index 00000000..b511a836 --- /dev/null +++ b/t/data/SPECS/orphans-1/t.spec @@ -0,0 +1,14 @@ +Summary: x +Name: t +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Requires: tt >= %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-1/tt1.spec b/t/data/SPECS/orphans-1/tt1.spec new file mode 100644 index 00000000..f4b8b35f --- /dev/null +++ b/t/data/SPECS/orphans-1/tt1.spec @@ -0,0 +1,14 @@ +Summary: x +Name: tt1 +Version: 1 +Release: 1 +License: x +Group: x +Url: x +Provides: tt = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/a-2.spec b/t/data/SPECS/orphans-2/a-2.spec new file mode 100644 index 00000000..0cd2afc8 --- /dev/null +++ b/t/data/SPECS/orphans-2/a-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: a +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/bb-2.spec b/t/data/SPECS/orphans-2/bb-2.spec new file mode 100644 index 00000000..0a57c173 --- /dev/null +++ b/t/data/SPECS/orphans-2/bb-2.spec @@ -0,0 +1,15 @@ +Summary: x +Name: bb +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Obsoletes: b < 2 +Provides: b = 2 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/c-2.spec b/t/data/SPECS/orphans-2/c-2.spec new file mode 100644 index 00000000..55d29981 --- /dev/null +++ b/t/data/SPECS/orphans-2/c-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: c +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: cc +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/d-2.spec b/t/data/SPECS/orphans-2/d-2.spec new file mode 100644 index 00000000..85bfbf5e --- /dev/null +++ b/t/data/SPECS/orphans-2/d-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: d +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/e-2.spec b/t/data/SPECS/orphans-2/e-2.spec new file mode 100644 index 00000000..538aa45c --- /dev/null +++ b/t/data/SPECS/orphans-2/e-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: e +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: ee2 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/ee2.spec b/t/data/SPECS/orphans-2/ee2.spec new file mode 100644 index 00000000..00a4cbf5 --- /dev/null +++ b/t/data/SPECS/orphans-2/ee2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: ee2 +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/f-2.spec b/t/data/SPECS/orphans-2/f-2.spec new file mode 100644 index 00000000..01fccf8c --- /dev/null +++ b/t/data/SPECS/orphans-2/f-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: f +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: ff2 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/ff2-2.spec b/t/data/SPECS/orphans-2/ff2-2.spec new file mode 100644 index 00000000..deb7e536 --- /dev/null +++ b/t/data/SPECS/orphans-2/ff2-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: ff2 +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Conflicts: ff1 < 2 +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/g-2.spec b/t/data/SPECS/orphans-2/g-2.spec new file mode 100644 index 00000000..d08c3677 --- /dev/null +++ b/t/data/SPECS/orphans-2/g-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: g +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: gg = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/gg-2.spec b/t/data/SPECS/orphans-2/gg-2.spec new file mode 100644 index 00000000..ccc6d4e7 --- /dev/null +++ b/t/data/SPECS/orphans-2/gg-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: gg +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/h-2.spec b/t/data/SPECS/orphans-2/h-2.spec new file mode 100644 index 00000000..2bbcc00d --- /dev/null +++ b/t/data/SPECS/orphans-2/h-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: h +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/l-2.spec b/t/data/SPECS/orphans-2/l-2.spec new file mode 100644 index 00000000..f1a456f1 --- /dev/null +++ b/t/data/SPECS/orphans-2/l-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: l +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: ll +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/m-2.spec b/t/data/SPECS/orphans-2/m-2.spec new file mode 100644 index 00000000..b3d7c233 --- /dev/null +++ b/t/data/SPECS/orphans-2/m-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: m +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: mm = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/mm-2.spec b/t/data/SPECS/orphans-2/mm-2.spec new file mode 100644 index 00000000..78c8e3ee --- /dev/null +++ b/t/data/SPECS/orphans-2/mm-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: mm +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: m +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/n-2.spec b/t/data/SPECS/orphans-2/n-2.spec new file mode 100644 index 00000000..438e8a2e --- /dev/null +++ b/t/data/SPECS/orphans-2/n-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: n +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: nn = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/nn-2.spec b/t/data/SPECS/orphans-2/nn-2.spec new file mode 100644 index 00000000..193e2903 --- /dev/null +++ b/t/data/SPECS/orphans-2/nn-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: nn +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: n = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/o-2.spec b/t/data/SPECS/orphans-2/o-2.spec new file mode 100644 index 00000000..0451c55c --- /dev/null +++ b/t/data/SPECS/orphans-2/o-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: o +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: oo%version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/oo2-2.spec b/t/data/SPECS/orphans-2/oo2-2.spec new file mode 100644 index 00000000..4a8568ed --- /dev/null +++ b/t/data/SPECS/orphans-2/oo2-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: oo2 +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: o = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/r-2.spec b/t/data/SPECS/orphans-2/r-2.spec new file mode 100644 index 00000000..ef6c3a75 --- /dev/null +++ b/t/data/SPECS/orphans-2/r-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: r +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-a-2.spec b/t/data/SPECS/orphans-2/req-a-2.spec new file mode 100644 index 00000000..d463a2ad --- /dev/null +++ b/t/data/SPECS/orphans-2/req-a-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-a +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-b-2.spec b/t/data/SPECS/orphans-2/req-b-2.spec new file mode 100644 index 00000000..7d7ca3a7 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-b-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-b +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-c-2.spec b/t/data/SPECS/orphans-2/req-c-2.spec new file mode 100644 index 00000000..205f2eb6 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-c-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-c +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-d-2.spec b/t/data/SPECS/orphans-2/req-d-2.spec new file mode 100644 index 00000000..d2ef1ddb --- /dev/null +++ b/t/data/SPECS/orphans-2/req-d-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-d +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-e-2.spec b/t/data/SPECS/orphans-2/req-e-2.spec new file mode 100644 index 00000000..9053971c --- /dev/null +++ b/t/data/SPECS/orphans-2/req-e-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-e +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-f-2.spec b/t/data/SPECS/orphans-2/req-f-2.spec new file mode 100644 index 00000000..4ced265b --- /dev/null +++ b/t/data/SPECS/orphans-2/req-f-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-f +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-g-2.spec b/t/data/SPECS/orphans-2/req-g-2.spec new file mode 100644 index 00000000..9794dd1c --- /dev/null +++ b/t/data/SPECS/orphans-2/req-g-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-g +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-h-2.spec b/t/data/SPECS/orphans-2/req-h-2.spec new file mode 100644 index 00000000..145a7310 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-h-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-h +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-l-2.spec b/t/data/SPECS/orphans-2/req-l-2.spec new file mode 100644 index 00000000..8422178c --- /dev/null +++ b/t/data/SPECS/orphans-2/req-l-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-l +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-m-2.spec b/t/data/SPECS/orphans-2/req-m-2.spec new file mode 100644 index 00000000..21767f34 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-m-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-m +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-n-2.spec b/t/data/SPECS/orphans-2/req-n-2.spec new file mode 100644 index 00000000..abc0b8d0 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-n-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-n +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-o-2.spec b/t/data/SPECS/orphans-2/req-o-2.spec new file mode 100644 index 00000000..f7d463fb --- /dev/null +++ b/t/data/SPECS/orphans-2/req-o-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-o +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-r-2.spec b/t/data/SPECS/orphans-2/req-r-2.spec new file mode 100644 index 00000000..a3c52f82 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-r-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-r +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-s-2.spec b/t/data/SPECS/orphans-2/req-s-2.spec new file mode 100644 index 00000000..38164a06 --- /dev/null +++ b/t/data/SPECS/orphans-2/req-s-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-s +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/req-t-2.spec b/t/data/SPECS/orphans-2/req-t-2.spec new file mode 100644 index 00000000..f008de2a --- /dev/null +++ b/t/data/SPECS/orphans-2/req-t-2.spec @@ -0,0 +1,13 @@ +Summary: x +Name: req-t +Version: 2 +Release: 1 +License: x +Group: x +Url: x +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/s-2.spec b/t/data/SPECS/orphans-2/s-2.spec new file mode 100644 index 00000000..5b4775e1 --- /dev/null +++ b/t/data/SPECS/orphans-2/s-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: s +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: ss +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/t-2.spec b/t/data/SPECS/orphans-2/t-2.spec new file mode 100644 index 00000000..8d5801ae --- /dev/null +++ b/t/data/SPECS/orphans-2/t-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: t +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Requires: tt >= %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/data/SPECS/orphans-2/tt2-2.spec b/t/data/SPECS/orphans-2/tt2-2.spec new file mode 100644 index 00000000..30937923 --- /dev/null +++ b/t/data/SPECS/orphans-2/tt2-2.spec @@ -0,0 +1,14 @@ +Summary: x +Name: tt2 +Version: 2 +Release: 1 +License: x +Group: x +Url: x +Provides: tt = %version +BuildRoot: %{_tmppath}/%{name} + +%description +x + +%files diff --git a/t/superuser--orphans.t b/t/superuser--orphans.t new file mode 100644 index 00000000..d9369a36 --- /dev/null +++ b/t/superuser--orphans.t @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +# a-1 upgrades to a-2 +# b-1 upgrades to bb-2 (via obsoletes) +# c-1 (requires cc) upgrades to c-2 (requires cc) +# d-1 (requires dd) upgrades to d-2 +# e-1 (requires ee1) upgrades to e-2 (requires ee2) +# f-1 (requires ff1) upgrades to f-2 (requires ff2), ff2 conflicts with ff1 +# g-1 (requires gg = 1) upgrades to g-2 (requires gg = 2) +# h-1 (suggests hh) upgrades to h-2 +# +# l-1 upgrades to l-2, l requires ll and ll requires l +# m-1 (requires mm = 1) upgrades to m-2 (requires mm = 2), mm requires m (circular dep) +# n-1 (requires nn = 1) upgrades to n-2 (requires nn = 2), nn-1 requires n-1, nn-2 requires n-2 (circular dep) +# o-1 (requires oo1) upgrades to o-2 (requires oo2), oo1 requires o = 1, oo2 requires o = 2 (circular dep) +# +# r-1 (requires rr) upgrades to r-2, rr1 provides rr, rr2 provides rr +# s-1 (requires ss1 and ss2) upgrades to s-2 (requires ss), ss1-2 provides ss, ss2-2 provides ss +# t-1 (requires tt >= 1) upgrades to t-2 (requires tt >= 2), tt1-1 provides tt = 1, tt1-2 provides tt = 2 +# +# req-a requires a, req-b requires b... +# +use strict; +use lib '.', 't'; +use helper; +use urpm::util; +use Test::More 'no_plan'; + +need_root_and_prepare(); + + +my $name = 'orphans'; +urpmi_addmedia("$name-1 $::pwd/media/$name-1"); +urpmi_addmedia("$name-2 $::pwd/media/$name-2"); + +# we want urpmi --auto-select to always check orphans (when not using --auto-orphans) +set_urpmi_cfg_global_options({ 'nb-of-new-unrequested-pkgs-between-auto-select-orphans-check' => 0 }); + + +test_auto_select_both('a', 'a', 'a-2'); +test_auto_select_both('b', 'b', 'bb-2'); +test_auto_select_both('c', 'c cc', 'c-2 cc-1'); +test_auto_select_both('d', 'd dd', 'd-2', 'dd-1'); +test_auto_select_both('e', 'e ee1', 'e-2 ee2-2', 'ee1-1'); +test_auto_select_both('f', 'f ff1', 'f-2 ff2-2'); +test_auto_select_both('g', 'g gg', 'g-2 gg-2'); +test_auto_select_both('h', 'h hh', 'h-2', 'hh-1'); +test_auto_select_both('l', 'l ll', 'l-2 ll-1'); +test_auto_select_both('m', 'm mm', 'm-2 mm-2'); +test_auto_select_both('n', 'n nn', 'n-2 nn-2'); +test_auto_select_both('o', 'o oo1', 'o-2 oo2-2'); +test_auto_select_both('r', 'r rr2', 'r-2', 'rr2-1'); +test_auto_select_both('s', 's ss1 ss2', 's-2 ss1-1 ss2-1'); +test_auto_select_both('t', 't tt1', 't-2 tt2-2', 'tt1-1'); + +test_auto_select(['r', 'rr1'], 'r rr1 rr2', 'r-2 rr1-1', 'rr2-1'); +#test_auto_select(['s ss1'], 's ss1 ss2', 's-2 ss1-1', 'ss2-1'); # this fails, but that's ok + +sub add_version1 { map { "$_-1-1" } split(' ', $_[0] || '') } +sub add_version2 { map { "$_-2-1" } split(' ', $_[0] || '') } +sub add_release { map { "$_-1" } split(' ', $_[0] || '') } +sub add_version1_s { join(' ', add_version1(@_)) } +sub add_version2_s { join(' ', add_version2(@_)) } +sub add_release_s { join(' ', add_release(@_)) } + +sub test_auto_select_both { + my ($pkg, $wanted_v1, $wanted_v2, $orphans_v2) = @_; + + $orphans_v2 ||= ''; + test_auto_select([$pkg], $wanted_v1, $wanted_v2, $orphans_v2); + test_auto_select(["req-$pkg"], "req-$pkg $wanted_v1", "req-$pkg-2", "$wanted_v2 $orphans_v2"); +} + +sub test_auto_select { + my ($req_v1, $wanted_v1, $wanted_v2, $orphans_v2) = @_; + test_auto_select_raw_urpmq_urpme ($req_v1, add_version1_s($wanted_v1), add_release_s($wanted_v2), add_release_s($orphans_v2)); + test_auto_select_raw_auto_orphans($req_v1, add_version1_s($wanted_v1), add_release_s($wanted_v2)); +} + +sub test_auto_select_raw_urpmq_urpme { + my ($req_v1, $wanted_v1, $wanted_v2, $orphans_v2) = @_; + print "# test_auto_select_raw_urpmq_urpme(@$req_v1, $wanted_v1, $wanted_v2)\n"; + urpmi("--media $name-1 --auto $_") foreach @$req_v1; + check_installed_fullnames(split ' ', $wanted_v1); + urpmi("--media $name-2 --auto --auto-select"); + check_installed_fullnames(split ' ', "$wanted_v2 $orphans_v2"); + is(run_urpm_cmd('urpmq -r --auto-orphans'), join('', sort map { "$_\n" } split ' ', $orphans_v2)); + urpme("--auto --auto-orphans"); + check_installed_fullnames_and_remove(split ' ', $wanted_v2); +} + +sub test_auto_select_raw_auto_orphans { + my ($req_v1, $wanted_v1, $wanted_v2) = @_; + print "# test_auto_select_raw_auto_orphans(@$req_v1, $wanted_v1, $wanted_v2)\n"; + urpmi("--media $name-1 --auto $_") foreach @$req_v1; + check_installed_fullnames(split ' ', $wanted_v1); + urpmi("--media $name-2 --auto --auto-select --auto-orphans"); + check_installed_fullnames_and_remove(split ' ', $wanted_v2); +} @@ -35,6 +35,7 @@ sub default_options { 'xml-info' => 'on-demand', 'max-round-robin-tries' => 5, 'days-between-mirrorlist-update' => 5, + 'nb-of-new-unrequested-pkgs-between-auto-select-orphans-check' => 10, }; } diff --git a/urpm/args.pm b/urpm/args.pm index 54013793..5b98d03a 100644 --- a/urpm/args.pm +++ b/urpm/args.pm @@ -84,6 +84,7 @@ my %options_spec = ( 'gui' => \$::gui, 'auto-select' => \$::auto_select, 'auto-update' => sub { $::auto_update = $::auto_select = 1 }, + 'auto-orphans' => \$options{auto_orphans}, 'no-remove|no-uninstall' => \$::no_remove, 'no-install|noinstall' => \$::no_install, 'keep!' => sub { $urpm->{options}{keep} = $_[1] }, @@ -409,12 +410,12 @@ foreach my $k ('allow-medium-change', 'auto', 'auto-select', 'force', 'expect-in $options_spec{gurpmi2} = $options_spec{gurpmi}; foreach my $k ("help|h", "version", "no-locales", "test!", "force", "root=s", "use-distrib=s", - 'repackage', 'noscripts', 'auto', + 'repackage', 'noscripts', 'auto', 'auto-orphans', "parallel=s") { $options_spec{urpme}{$k} = $options_spec{urpmi}{$k}; } -foreach my $k ("root=s", "nolock", "use-distrib=s", "skip=s", "prefer=s", "synthesis=s", 'suggests', 'no-suggests', 'allow-suggests') +foreach my $k ("root=s", "nolock", "use-distrib=s", "skip=s", "prefer=s", "synthesis=s", 'suggests', 'no-suggests', 'allow-suggests', 'auto-orphans') { $options_spec{urpmq}{$k} = $options_spec{urpmi}{$k}; } diff --git a/urpm/cfg.pm b/urpm/cfg.pm index 53f610ee..f8b98ed6 100644 --- a/urpm/cfg.pm +++ b/urpm/cfg.pm @@ -151,6 +151,7 @@ sub load_config_raw { |removable |md5sum |limit-rate + |nb-of-new-unrequested-pkgs-between-auto-select-orphans-check |xml-info |excludepath |split-(?:level|length) diff --git a/urpm/main_loop.pm b/urpm/main_loop.pm index 3dec70c8..224a9909 100644 --- a/urpm/main_loop.pm +++ b/urpm/main_loop.pm @@ -26,6 +26,7 @@ use urpm::msg; use urpm::install; use urpm::media; use urpm::select; +use urpm::orphans; use urpm::get_pkgs; use urpm::signature; use urpm::util qw(untaint difference2 intersection member partition); @@ -209,6 +210,9 @@ foreach my $set (@{$state->{transaction} || []}) { callback_trans => $callbacks->{trans}, callback_report_uninst => $callbacks->{callback_report_uninst}, ); + + urpm::orphans::add_unrequested($urpm, $state); + my @l = urpm::install::install($urpm, $to_remove, \%transaction_sources_install, \%transaction_sources, diff --git a/urpm/orphans.pm b/urpm/orphans.pm new file mode 100644 index 00000000..fa8bb28a --- /dev/null +++ b/urpm/orphans.pm @@ -0,0 +1,341 @@ +package urpm::orphans; + +use urpm::util; +use urpm::msg; +use urpm; + +# $Id: select.pm 243120 2008-07-01 12:24:34Z pixel $ + +my $fullname2name_re = qr/^(.*)-[^\-]*-[^\-]*\.[^\.\-]*$/; + +#- side-effects: none +sub installed_packages_packed { + my ($urpm) = @_; + + my $db = urpm::db_open_or_die_($urpm); + my @l; + $db->traverse(sub { + my ($pkg) = @_; + $pkg->pack_header; + push @l, $pkg; + }); + \@l; +} + +#- side-effects: none +sub unrequested_list__file { + my ($urpm) = @_; + "$urpm->{root}/var/lib/urpmi/installed-through-deps.list"; +} +#- side-effects: none +sub unrequested_list { + my ($urpm) = @_; + +{ map { + chomp; + s/\s+\(.*\)$//; + $_ => 1; + } cat_(unrequested_list__file($urpm)) }; +} + +#- side-effects: +#- + those of _installed_req_and_unreq_and_update_unrequested_list (<root>/var/lib/urpmi/installed-through-deps.list) +sub _installed_req_and_unreq { + my ($urpm) = @_; + my ($req, $unreq, $_unrequested) = _installed_req_and_unreq_and_update_unrequested_list($urpm); + ($req, $unreq); +} +#- side-effects: +#- + those of _installed_req_and_unreq_and_update_unrequested_list (<root>/var/lib/urpmi/installed-through-deps.list) +sub _installed_and_unrequested_lists { + my ($urpm) = @_; + my ($pkgs, $pkgs2, $unrequested) = _installed_req_and_unreq_and_update_unrequested_list($urpm); + push @$pkgs, @$pkgs2; + ($pkgs, $unrequested); +} +#- side-effects: <root>/var/lib/urpmi/installed-through-deps.list +sub _installed_req_and_unreq_and_update_unrequested_list { + my ($urpm) = @_; + + my $pkgs = installed_packages_packed($urpm); + + $urpm->{debug}("reading and cleaning " . unrequested_list__file($urpm)) if $urpm->{debug}; + my $unrequested = unrequested_list($urpm); + my ($unreq, $req) = partition { $unrequested->{$_->name} } @$pkgs; + + # update the list (to filter dups and now-removed-pkgs) + output_safe(unrequested_list__file($urpm), + join('', sort map { $_->name . "\n" } @$unreq), + ".old"); + + ($req, $unreq, $unrequested); +} + + +#- side-effects: none +sub _selected_unrequested { + my ($urpm, $selected) = @_; + + map { + if (my $from = $selected->{$_}{from}) { + ($urpm->{depslist}[$_]->name => "(required by " . $from->fullname . ")"); + } elsif ($selected->{$_}{suggested}) { + ($urpm->{depslist}[$_]->name => "(suggested)"); + } else { + (); + } + } keys %$selected; +} +#- side-effects: $o_unrequested_list +sub _renamed_unrequested { + my ($urpm, $rejected, $o_unrequested_list) = @_; + + my @obsoleted = grep { $rejected->{$_}{obsoleted} } keys %$rejected or return; + + # we have to read the list to know if the old package was marked "unrequested" + my $current = $o_unrequested_list || unrequested_list($urpm); + + my %l; + foreach my $fn (@obsoleted) { + my ($n) = $fn =~ $fullname2name_re; + $current->{$n} or next; + + my ($new_fn) = keys %{$rejected->{$fn}{closure}}; + my ($new_n) = $new_fn =~ $fullname2name_re; + $l{$new_n} = "(obsoletes $fn)"; + } + %l; +} +sub _new_unrequested { + my ($urpm, $state) = @_; + ( + _selected_unrequested($urpm, $state->{selected}), + _renamed_unrequested($urpm, $state->{rejected}), + ); +} +#- side-effects: <root>/var/lib/urpmi/installed-through-deps.list +sub add_unrequested { + my ($urpm, $state) = @_; + + my %l = _new_unrequested($urpm, $state); + append_to_file(unrequested_list__file($urpm), join('', map { "$_\t\t$l{$_}\n" } keys %l)); +} + +#- we don't want to check orphans on every auto-select, +#- doing it only after many packages have been added +#- +#- side-effects: none +sub check_unrequested_orphans_after_auto_select { + my ($urpm) = @_; + my $f = unrequested_list__file($urpm); + my $nb_added = wc_l($f) - wc_l("$f.old"); + $nb_added >= $urpm->{options}{'nb-of-new-unrequested-pkgs-between-auto-select-orphans-check'}; +} + +#- this function computes wether removing $toremove packages will create +#- unrequested orphans. +#- +#- it does not return the new orphans since "whatsuggests" is not available, +#- if it detects there are new orphans, _all_unrequested_orphans() +#- must be used to have the list of the orphans +#- +#- side-effects: none +sub unrequested_orphans_after_remove { + my ($urpm, $toremove) = @_; + + my $db = urpm::db_open_or_die_($urpm); + my %toremove = map { $_ => 1 } @$toremove; + _unrequested_orphans_after_remove_once($urpm, $db, unrequested_list($urpm), \%toremove); +} +#- side-effects: none +sub _unrequested_orphans_after_remove_once { + my ($urpm, $db, $unrequested, $toremove) = @_; + + my @requires; + foreach my $fn (keys %$toremove) { + my ($n) = $fn =~ $fullname2name_re; + + $db->traverse_tag('name', [ $n ], sub { + my ($p) = @_; + $p->fullname eq $fn or return; + push @requires, $p->requires; + }); + } + + foreach my $req (uniq(@requires)) { + $db->traverse_tag_find('whatprovides', $req, sub { + my ($p) = @_; + $toremove->{$p->fullname} and return; # already done + $unrequested->{$p->name} or return; + $p->provides_overlap($req) or return; + + # cool we have a potential "unrequested" package newly unneeded + if (_check_potential_unrequested_package_newly_unneeded($urpm, $db, $toremove, $p)) { + $urpm->{debug}("installed " . $p->fullname . " can now be removed") if $urpm->{debug}; + return 1; + } else { + $urpm->{debug}("installed " . $p->fullname . " can not be removed") if $urpm->{debug}; + } + 0; + }) and return 1; + } + 0; +} +#- side-effects: none +sub _check_potential_unrequested_package_newly_unneeded { + my ($urpm, $db, $toremove, $pkg) = @_; + + my $required_maybe_loop; + + foreach my $prop ($pkg->provides) { + _check_potential_unrequested_provide_newly_unneeded($urpm, $db, $toremove, + scalar($pkg->fullname), $prop, \$required_maybe_loop) + and return; + } + + if ($required_maybe_loop) { + my ($fullname, @provides) = @$required_maybe_loop; + $urpm->{debug}("checking wether $fullname is a depency loop") if $urpm->{debug}; + + # doing it locally, since we may fail (and so we must backtrack this change) + my %ignore = %$toremove; + $ignore{$pkg->fullname} = 1; + + foreach my $prop (@provides) { + _check_potential_unrequested_provide_newly_unneeded($urpm, $db, \%ignore, + $fullname, $prop, \$required_maybe_loop) + and return; + } + } + 1; +} +#- side-effects: none +sub _check_potential_unrequested_provide_newly_unneeded { + my ($urpm, $db, $toremove, $fullname, $prop, $required_maybe_loop) = @_; + + my ($prov, $range) = URPM::property2name_range($prop) or return; + + $db->traverse_tag_find('whatrequires', $prov, sub { + my ($p2) = @_; + $toremove->{$p2->fullname} and return 0; # this one is going to be removed, skip it + + foreach ($p2->requires) { + my ($pn, $ps) = URPM::property2name_range($_) or next; + if ($pn eq $prov && URPM::ranges_overlap($ps, $range)) { + if ($$required_maybe_loop) { + $urpm->{debug}(" installed " . $p2->fullname . " still requires " . $fullname) if $urpm->{debug}; + return 1; + } + $urpm->{debug}(" installed " . $p2->fullname . " may still requires " . $fullname) if $urpm->{debug}; + $$required_maybe_loop = [ scalar $p2->fullname, $p2->provides ]; + } + } + 0; + }); +} + +#- returns the list of "unrequested" orphans. +#- +#- side-effects: none +sub _all_unrequested_orphans { + my ($req, $unreq) = @_; + + my (%l, %provides); + foreach my $pkg (@$unreq) { + $l{$pkg->name} = $pkg; + push @{$provides{$_}}, $pkg foreach $pkg->provides_nosense; + } + + while (my $pkg = shift @$req) { + foreach my $prop ($pkg->requires) { + my $n = URPM::property2name($prop); + foreach my $p (@{$provides{$n} || []}) { + if ($p != $pkg && $l{$p->name} && $p->provides_overlap($prop)) { + delete $l{$p->name}; + push @$req, $p; + } + } + } + } + + [ values %l ]; +} + + +#- side-effects: $state->{orphans_to_remove} +#- + those of _installed_and_unrequested_lists (<root>/var/lib/urpmi/installed-through-deps.list) +sub compute_future_unrequested_orphans { + my ($urpm, $state) = @_; + + $urpm->{log}("computing unrequested orphans"); + + my ($current_pkgs, $unrequested) = _installed_and_unrequested_lists($urpm); + + put_in_hash($unrequested, { _new_unrequested($urpm, $state) }); + + my %toremove = map { $_ => 1 } URPM::removed_or_obsoleted_packages($state); + my @pkgs = grep { !$toremove{$_->fullname} } @$current_pkgs; + push @pkgs, map { $urpm->{depslist}[$_] } keys %{$state->{selected} || {}}; + + my ($unreq, $req) = partition { $unrequested->{$_->name} } @pkgs; + + $state->{orphans_to_remove} = _all_unrequested_orphans($req, $unreq); + + # nb: $state->{orphans_to_remove} is used when computing ->selected_size +} + +#- it is quite fast. the slow part is the creation of $installed_packages_packed +#- (using installed_packages_packed()) +# +#- side-effects: +#- + those of _installed_req_and_unreq (<root>/var/lib/urpmi/installed-through-deps.list) +sub get_orphans { + my ($urpm) = @_; + + $urpm->{log}("computing unrequested orphans"); + + my ($req, $unreq) = _installed_req_and_unreq($urpm); + _all_unrequested_orphans($req, $unreq); +} +sub get_now_orphans_msg { + my ($urpm) = @_; + + my $orphans = get_orphans($urpm); + my @orphans = map { scalar $_->fullname } @$orphans or return ''; + + P("The following package is now orphan, use \"urpme --auto-orphans\" to remove it.", + "The following packages are now orphans, use \"urpme --auto-orphans\" to remove them.", scalar(@orphans)) + . "\n" . add_leading_spaces(join("\n", @orphans) . "\n"); +} + +#- side-effects: none +sub add_leading_spaces { + my ($s) = @_; + $s =~ s/^/ /gm; + $s; +} + +#- side-effects: none +sub installed_leaves { + my ($urpm, $o_discard) = @_; + + my $packages = installed_packages_packed($urpm); + + my (%l, %provides); + foreach my $pkg (@$packages) { + next if $o_discard && $o_discard->($pkg); + $l{$pkg->name} = $pkg; + push @{$provides{$_}}, $pkg foreach $pkg->provides_nosense; + } + + foreach my $pkg (@$packages) { + foreach my $prop ($pkg->requires) { + my $n = URPM::property2name($prop); + foreach my $p (@{$provides{$n} || []}) { + $p != $pkg && $p->provides_overlap($prop) and + delete $l{$p->name}; + } + } + } + + [ values %l ]; +} @@ -26,6 +26,7 @@ use urpm::msg; use urpm::install; use urpm::media; use urpm::select; +use urpm::orphans; $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"; @@ -44,6 +45,7 @@ This is free software and may be redistributed under the terms of the GNU GPL. usage: ", $urpm::VERSION) . N(" --help - print this help message. ") . N(" --auto - automatically select a package in choices. +") . N(" --auto-orphans - remove orphans ") . N(" --test - verify if the removal can be achieved correctly. ") . N(" --force - force invocation even if some packages do not exist. ") . N(" --parallel - distributed urpmi across machines of alias. @@ -62,7 +64,7 @@ usage: my @origARGV = @ARGV; my $urpm = urpm->new_parse_cmdline or exit(1); my @cmdline_pkgs_to_remove = @ARGV; -@cmdline_pkgs_to_remove || $options{matches} or usage(); +@cmdline_pkgs_to_remove || $options{matches} || $options{auto_orphans} or usage(); my $state = {}; @@ -89,7 +91,9 @@ urpm::media::configure($urpm, ); #- examine packages... -my @toremove = urpm::select::find_packages_to_remove( +my @toremove; +if (@cmdline_pkgs_to_remove || $options{matches}) { + @toremove = urpm::select::find_packages_to_remove( $urpm, $state, \@cmdline_pkgs_to_remove, @@ -118,13 +122,35 @@ my @toremove = urpm::select::find_packages_to_remove( 0; }, ) or $urpm->{fatal}(0, N("Nothing to remove")); +} + +my $may_be_orphans = 1; +if (@toremove && !$urpm->{options}{auto}) { + urpm::orphans::unrequested_orphans_after_remove($urpm, \@toremove) + or $may_be_orphans = 0; +} + +my @toremove_no_orphans = @toremove; +my @orphans; +if ($options{auto_orphans} && $may_be_orphans) { + urpm::orphans::compute_future_unrequested_orphans($urpm, $state); + @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}; + + push @toremove, @orphans; + if (!@toremove) { + print N("No orphans to remove"), "\n"; + exit 0; + } +} my $msg = P("To satisfy dependencies, the following package will be removed", "To satisfy dependencies, the following %d packages will be removed", scalar(@toremove), scalar(@toremove)) . sprintf(" (%s)", formatXiB(-$urpm->selected_size($state))) . ":\n" - . add_leading_spaces(urpm::select::translate_why_removed($urpm, $state, @toremove)) . "\n"; + . add_leading_spaces(urpm::select::translate_why_removed($urpm, $state, @toremove_no_orphans)) . "\n" + . (@orphans ? P("(orphan package)", "(orphan packages)", scalar(@orphans)) . "\n" . + add_leading_spaces(join("\n", @orphans) . "\n") : ()); if ($urpm->{options}{auto}) { $test and print STDOUT $msg; @@ -148,6 +174,10 @@ my @errors = $parallel if (@errors) { #- Warning : the following message is parsed in urpm::parallel_* $urpm->{fatal}(2, N("Removal failed") . ":\n" . join("\n", map { "\t$_" } @errors)); +} elsif ($may_be_orphans && !$options{auto_orphans} && !$test) { + if (my $msg = urpm::orphans::get_now_orphans_msg($urpm)) { + print "\n", $msg; + } } sub add_leading_spaces { @@ -83,6 +83,7 @@ usage: ") . N(" --auto-update - update media then upgrade the system. ") . N(" --no-md5sum - disable MD5SUM file checking. ") . N(" --force-key - force update of gpg key. +") . N(" --auto-orphans - remove orphans without asking ") . N(" --no-suggests - do not auto select \"suggested\" packages. ") . N(" --no-uninstall - never ask to uninstall a package, abort the installation. ") . N(" --no-install - don't install packages (only download) @@ -239,7 +240,7 @@ if ($restricted) { #- force some options foreach (qw(keep verify-rpm)) { $urpm->{options}{$_} = 1 } #- forbid some other options - urpm::error_restricted($urpm) if $urpm->{root} || $options{usedistrib} || $force || $env || $parallel || $options{synthesis} || $auto_update; + urpm::error_restricted($urpm) if $urpm->{root} || $options{usedistrib} || $force || $env || $parallel || $options{synthesis} || $auto_update || $options{auto_orphans}; foreach (qw(allow-nodeps allow-force curl-options rsync-options wget-options prozilla-options noscripts)) { urpm::error_restricted($urpm) if $urpm->{options}{$_}; } @@ -587,6 +588,16 @@ my @to_install = @{$urpm->{depslist}}[sort { $a <=> $b } keys %{$state->{selecte } } + +if (@to_install && $options{auto_orphans}) { + urpm::orphans::compute_future_unrequested_orphans($urpm, $state); + if (my @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}) { + print P("The following orphan package will be removed.", + "The following orphan packages will be removed.", scalar(@orphans)) + . "\n" . urpm::orphans::add_leading_spaces(join("\n", @orphans) . "\n"); + } +} + foreach my $pkg (@to_install) { #- reflect change in flag usage, now requested is set whatever a package is selected or not, #- but required is always set (so a required but not requested is a pure dependency). @@ -669,6 +680,14 @@ my $exit_code = urpm::main_loop::run($urpm, $state, } }); +if ($exit_code == 0 && $auto_select && !$options{auto_orphans}) { + if (urpm::orphans::check_unrequested_orphans_after_auto_select($urpm)) { + if (my $msg = urpm::orphans::get_now_orphans_msg($urpm)) { + print "\n", $msg; + } + } +} + unless ($env || $options{nolock}) { $urpmi_lock->unlock; $rpm_lock->unlock if $rpm_lock; diff --git a/urpmi.bash-completion b/urpmi.bash-completion index 09852b97..d244d282 100644 --- a/urpmi.bash-completion +++ b/urpmi.bash-completion @@ -95,7 +95,7 @@ _urpmi() # add dangereous option for everything else as rurpmi if [[ ${COMP_WORDS[0]} != *rurpmi ]]; then options="$options --root --use-distrib --env \ - --replacepkgs --justdb \ + --auto-orphans --replacepkgs --justdb \ --allow-nodeps --allow-force --no-suggests --force \ --noscripts --auto-update --keep --nokeep \ --verify-rpm" @@ -162,7 +162,8 @@ _urpmq() # return list of available options COMPREPLY=( $( compgen -W "$common_options -d -u -m -a -c -y -s -i -g -p \ -r -f -l --update --media --excludemedia \ - --sortmedia --synthesis --auto-select --no-suggests --fuzzy --keep --nokeep \ + --sortmedia --synthesis --auto-select --auto-orphans \ + --no-suggests --fuzzy --keep --nokeep \ --list --list-url --list-media --list-nodes --list-aliases \ --src --sources --provides --requires --summary --sourcerpm --force --parallel --wget --curl --prozilla \ --changelog --conflicts --proxy --proxy-user --env --dump-config \ @@ -188,7 +189,7 @@ _urpme() if [[ "$cur" == -* ]]; then # return list of available options COMPREPLY=( $( compgen -W "$common_options -a --auto --test \ - --parallel --noscripts" -- $cur ) ) + --auto-orphans --parallel --noscripts" -- $cur ) ) else # return list of available packages _rpm_installed_packages @@ -50,6 +50,7 @@ usage: ") . N(" --sortmedia - sort media according to substrings separated by comma. ") . N(" --synthesis - use the given synthesis instead of urpmi db. ") . N(" --auto-select - automatically select packages to upgrade the system. +") . N(" --auto-orphans - list orphans ") . N(" --no-suggests - do not auto select \"suggested\" packages. ") . N(" --fuzzy - impose fuzzy search (same as -y). ") . N(" --keep - keep existing packages if possible, reject requested @@ -137,6 +138,27 @@ $options{nodepslist} = $options{list_aliases} || $options{list_url}; $options{nolock} = 1 if $options{nodepslist}; +#- print sub for query. +my $pkg_to_string = sub { + my ($pkg) = @_; + my $str = ''; + $options{group} and $str .= $pkg->group . '/'; + $str .= $pkg->name; + $options{version} and $str .= '-' . $pkg->version; + $options{release} and $str .= '-' . $pkg->release; + $options{arch} and $str .= '.' . $pkg->arch; + $str; +}; + +if ($options{auto_orphans}) { + !@names && !@src_names or $urpm->{fatal}(1, N("usage: \"urpmq --auto-orphans\" with no argument")); + $options{env} and $urpm->{fatal}(1, N("Can't use %s with %s", '--env', '--auto-orphans')); + require urpm::orphans; + my $orphans = urpm::orphans::get_orphans($urpm); + print "$_\n" foreach sort map { $pkg_to_string->($_) } @$orphans; + exit 0; +} + if ($options{env}) { print N("using specific environment on %s\n", $options{env}); #- setting new environment. @@ -487,14 +509,7 @@ $rpm_lock and $rpm_lock->unlock; #- print sub for query. my $query_sub = sub { my ($id) = @_; - my $pkg = $urpm->{depslist}[$id]; - my $str = ''; - $options{group} and $str .= $pkg->group . '/'; - $str .= $pkg->name; - $options{version} and $str .= '-' . $pkg->version; - $options{release} and $str .= '-' . $pkg->release; - $options{arch} and $str .= '.' . $pkg->arch; - $str; + $pkg_to_string->($urpm->{depslist}[$id]); }; my %hack_only_one; |