Ubuntu 16.04: virtual packageについて

debパッケージのvirtual packageについて記載します。

1 virtual packageとは

awk-original, mawk, gawkのように、awkの機能を提供するパッケージがいくつかあります。これらはライセンス、実装、詳細な機能に違いがあります。awkの機能を利用するユーザはパッケージを選択することが出来ます。

awkの機能を依存するパッケージでこの選択の余地が問題となります。ユーザはmawkを選択しているのに、awkの機能を利用するパッケージがgawkを依存している場合、mawkとgawkがコンフリクトすることになります。

そこで、awkというvirtual packageを用意し、awkの機能を依存するパッケージではawkというvirtual packageを依存するようにします。また、awk-original, mawk, gawkはawkという機能をprovideします。これによりユーザの選択と依存パッケージがコンフリクトすることがなくなります。

2 virtual packageかどうかの判定

apt showを実行した際に"not a real package"という文字列が含まれるので、それを判定に使います。

$ apt show awk | grep "not a real package"
State: not a real package (virtual)

3 virtual packageをprovideするパッケージ

apt installでvirtual packageを指定すると、"Package xxx is a virtual package provided by:"でprovideするパッケージの一覧が表示されます。ここでは-sオプションを用いてシミュレーション実行します。

$ apt install awk -s awk
NOTE: This is only a simulation!
      apt-get needs root privileges for real execution.
      Keep also in mind that locking is deactivated,
      so don't depend on the relevance to the real current situation!
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package awk is a virtual package provided by:
  original-awk:i386 2012-12-20-5
  original-awk 2012-12-20-5
  mawk:i386 1.3.3-17ubuntu2
  gawk:i386 1:4.1.3+dfsg-0.1
  mawk 1.3.3-17ubuntu2
  gawk 1:4.1.3+dfsg-0.1
You should explicitly select one to install.

E: Package 'awk' has no installation candidate

4 virtual packageをprovideパッケージに変換する

以下のようなスクリプトでvirtual packageをprovideパッケージに変換できます。

#!/bin/sh

if [ $# -ne 1 ]; then
  prog=`basename ${0}`
  echo "usage: ${prog} <virtual package>"
  exit 1
fi

TMP=`mktemp -t a.sh.XXXXXX`
trap "rm $TMP* 2>/dev/null" 0

check_virtual_package()
{
  apt show $1 2> /dev/null | grep "not a real package" > /dev/null
  return $?
}

print_provide_package()
{
  apt install -s $1 > ${TMP} 2> /dev/null

  state=0
  pkgs=""
  while read line; do
    if [ "${line}x" = "Package $1 is a virtual package provided by:x" ]; then
      state=1
    elif [ ${state} -eq 1 -a -n "${line}" ]; then
      pkg=`echo ${line} | awk '{ print $1 }'`
      echo ${pkg} | grep -v ':i386' > /dev/null && pkgs="${pkg} ${pkgs}"
    fi
  done < ${TMP}

  echo ${pkgs}
}

check_virtual_package $1
if [ $? -eq 0 ]; then
  print_provide_package $1
else
  echo $1
fi