[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#275379: apt-get: please support "satisfy"



Hi,

On Mon, 17 Oct 2016 07:20:43 +0800 Paul Wise <pabs@debian.org> wrote:
> I too would like to see a satisfy subcommand that could be run like this:
> 
> apt satisfy 'python3, pyflakes3 | pyflakes (>= 0.7.3), pyflakes3 | pyflakes (<< 1.1.0-1)'
> 
> The reason I want this is so that I can make check-all-the-things run apt
> for checks that have missing commands and get the right packages installed
> no matter what the distribution it is being run on.
> 
> $ check-all-the-things --install apt --checks pyflakes3
> sudo apt satisfy 'python3, pyflakes3 | pyflakes (>= 0.7.3), pyflakes3 | pyflakes (<< 1.1.0-1)'
> 
> Right now there are workarounds that can be used for this being missing:
> 
> * create a debian/control file containing a single Build-Depends line (apt > 1.2.2)

this has the disadvantage of always pulling in the build-essential package.

> * create a full Debian binary package containing the right Depends

This has the disadvantage that it installs a meta-package on the user's system.

> * Use python-apt to do the resolution and emit `apt install pkg=1.2.3` commands?

I don't see a way to achieve this with python-apt. Even when manually iterating
through the given dependency string and checking which package in the apt cache
satisfies the dependency, the solution would not always be correct. Here is an
example in which this approach would fail:

Suppose there are the packages A, B, C and D. A depends on D and D conflicts
with C. Now the wants the following resolved:

'A | B, C'

With the algorithm sketched above, A and C would be picked for installation but
the solution would be invalid because A and C conflict via D. To avoid this
situation, the code has to traverse all dependency trees which would in turn
lead to the implementation of a full-fledged resolver. Certainly this is not
desired.

> The first two are easy but I'm not sure about the last one.

I see no way to use python-apt for tapping into apt's own resolver.

On IRC you also mentioned the possibility to use dose3. A solution using dose3
would look the following way: Use apt-get indextargets to get the list of
Packages files apt uses and then use "apt-helper cat-file" to feed the
information to dose-deb-coinstall as the background packages. Then as the
foreground packages, pass a dummy binary package containing a Depends line that
you want to satisfy. The tool will then output an installation set in deb822
format on standard output. While this will create a valid solution, it might
not be a very good solution because the package selection does not take into
account the packages that are already installed on the user's system and it
also does not adhere to apt's pinning or its idea about installing real
packages before virtual ones.

In this email I want to create a fourth option. It takes the installed packages
into account, uses the apt resolver and even respects pinning values. We'll be
using apt's EDSP interface. Essentially the solution works by creating an EDSP
file that represents the current state of the system and then adding a custom
header and dummy binary package to it and feed all that to
/usr/lib/apt/solvers/apt. The EDSP returned by the program is then the solution
that can be mapped to package name/version/arch triplets which can be used to
assemble an apt-get install command line.

You can find my script attached. You use it like this:

$ ./apt-satisfy "apache2 (>= 1.3.37) | httpd"
apt install libaprutil1:amd64=1.5.4-3 libaprutil1-dbd-sqlite3:amd64=1.5.4-3 apache2-data:all=2.4.23-8 libaprutil1-ldap:amd64=1.5.4-3 apache2-bin:amd64=2.4.23-8 apache2:amd64=2.4.23-8 apache2-utils:amd64=2.4.23-8
apt-mark auto libaprutil1:amd64 libaprutil1-dbd-sqlite3:amd64 apache2-data:all libaprutil1-ldap:amd64 apache2-bin:amd64 apache2:amd64 apache2-utils:amd64

It prints two commands that you can directly execute. The first command
installs the right packages and the second command marks the newly installed
packages as automatically installed. The latter is to make sure that these
packages which have no real origin (the user never directly requested a real
package to be installed) can easily be autoremoved. In the context of
check-all-the-things, marking the packages as auto will not even lead to an
autoremoval because check-all-the-things Recommends them.

What do you think?

Thanks!

cheers, josch
#!/bin/sh

set -eu

depends=$@

edspfile=$(mktemp)
solution=$(mktemp)

trap "rm -r \"$edspfile\" \"$solution\"" EXIT

# simulate installation of a random package - we choose apt because that has to exist
#
# we expect the dump solver to fail with exit 100
APT_EDSP_DUMP_FILENAME="$edspfile" apt-get --simulate install --solver dump apt >/dev/null 2>&1 && [ $? -eq 100 ]

request=$(grep-dctrl -F Request '' -s Request -n "$edspfile")
architecture=$(grep-dctrl -F Request '' -s Architecture -n "$edspfile")
architectures=$(grep-dctrl -F Request '' -s Architectures -n "$edspfile")

# generate the APT-ID of the dummy package from the largest id plus one
newid=$(grep-dctrl -F Package '' -s APT-ID -n "$edspfile" | sort -n | tail -1)
newid=$((newid+1))

# Replace the EDSP header and add a dummy package at the top
{
	cat << END
Request: $request
Architecture: $architecture
Architectures: $architectures
Install: apt-satisfy-dummy:$architecture

Package: apt-satisfy-dummy
Architecture: $architecture
Version: 1
APT-ID: $newid
Depends: $depends
APT-Pin: 990

END
	grep-dctrl -F Package '' "$edspfile";
} | /usr/lib/apt/solvers/apt > "$solution"

# FIXME: instead of using grep and cat we want to use grep-dctrl but
# unfortunately the EDSP that /usr/lib/apt/solvers/apt outputs is not valid
# deb822
if grep Error: "$solution"; then
	cat "$solution"
	exit
fi

selector=$(grep-dctrl -F Install '' -n -s Install "$solution" | paste -s -d"|")

install=$(grep-dctrl --eregex -F APT-ID "^($selector)$" -n -s Package,Architecture,Version "$edspfile" \
	| paste -sd ":=  " )
echo apt install $install

auto=$(grep-dctrl --eregex -F APT-ID "^($selector)$" -n -s Package,Architecture "$edspfile" \
	| paste -sd ":  " )
echo apt-mark auto $auto

Attachment: signature.asc
Description: signature


Reply to: