人間になりたい類人猿

人間以前の技術屋ブログ

yumでインストールするパッケージの依存関係を再帰的に知りたかった

はじめに

yum deplist [パッケージ]でそのパッケージのインストールする際の依存関係がわかるが、
「じゃあ依存関係にあるパッケージの依存関係はどうなん?」というのを見てみたくなった。

ので作った。

利用用途?知らない。
何か「yumで勝手にインストールするな!依存関係を全て調べろ!」とかいう人に出してあげれば良いんじゃん?
知らんけど。再帰関数あまり使わないな練習しよと思ってなんとなーくネタが出来たので作ったまで

ロジック関連

yum deplist [パッケージ]の結果は以下のようになる。

package: httpd.x86_64 2.4.52-1.amzn2
  dependency: /bin/sh
   provider: bash.x86_64 4.2.46-34.amzn2
  dependency: /etc/mime.types
   provider: mailcap.noarch 2.1.41-2.amzn2
  dependency: config(httpd) = 2.4.52-1.amzn2
   provider: httpd.x86_64 2.4.52-1.amzn2
  dependency: httpd-filesystem
   provider: httpd-filesystem.noarch 2.4.52-1.amzn2
  dependency: libc.so.6()(64bit)
   provider: glibc.x86_64 2.26-57.amzn2
  dependency: libc.so.6(GLIBC_2.14)(64bit)
   provider: glibc.x86_64 2.26-57.amzn2
  dependency: libc.so.6(GLIBC_2.2.5)(64bit)
   provider: glibc.x86_64 2.26-57.amzn2

このprovider:以下が依存関係が入っているパッケージなので、このyum deplistの結果を受け取り、正規表現でprovider:の後ろをリストで取得。
各パッケージに大して再度yum deplistすれば良い。

ただし以下のような注意点がある。
①↑の通り同じproviderが複数出るパターンが有る。
 →重複は削除する(別に出してもいいけどノイズになるので)
②依存パッケージの依存関係を調べたら、上位で依存関係として出てきたパッケージが出るパターンがある。(無限ループする)
 →すでに上位で依存すると分かっているなら下位では調べない。

例えば以下みたいな感じ

yum deplist glibc.x86_64 2.26-57.amzn2
→結果にprovider: glibc-minimal-langpack.x86_64 2.26-57.amzn2
→yum deplist glibc-minimal-langpack.x86_64 2.26-57.amzn2
→結果にprovider: glibc.x86_64 2.26-57.amzn2(↑と同じ)
→yum deplist glibc.x86_64 2.26-57.amzn2
→以下無限ループ

これを考慮して出力が以下になるようにインデント数を調整する

解析したいパッケージ
   依存パッケージA
    依存パッケージA-1
   依存パッケージB
    依存パッケージB-1
    依存パッケージB-2

出来上がったのがこちら

# coding: UTF-8
import subprocess
import traceback
import re
import sys
from collections import OrderedDict

#上位パッケージですでに依存関係があると分かっている物を保存しておくメモ(下位パッケージで上位と同じパッケージが出てくるパターンが有った。無限ループになるのでメモ化)
memo = []

def analyzeDependency(indentCount,package):
  """
  依存関係を解析する
  """
  printDependencyPackage(indentCount,package)

  #依存関係取得
  dependPackages = getDependencyPackages(package)

  if len(dependPackages) > 0:
    for dependPackage in dependPackages:
      if dependPackage not in memo:
        #メモに追加
        memo.append(dependPackage)
        analyzeDependency(indentCount+1,dependPackage)
      else:
        if isPrintFull:
          printDependencyPackage(indentCount+1,dependPackage+"(already depend)")

def getDependencyPackages(package):
  """
  指定されたパッケージの依存関係を取得
  """
  cmd = "yum deplist " + package
  res = execCmd(cmd)
  
  #依存関係のあるパッケージのリストを取得
  dependPackages = re.findall("provider: (.*)",res.decode("utf-8"))

  #重複削除
  return list(OrderedDict.fromkeys(dependPackages))

def printDependencyPackage(indentCount,package):
  """
  出力
  """
  indentStr = ""
  for i in range(indentCount):
    indentStr += " "
  
  print(indentStr+package)

def execCmd(cmd):
  """
  コマンド実行
  """
  try:
    res = subprocess.check_output(cmd,shell=True,stderr=subprocess.DEVNULL)
    return res
  except Exception as e:
    print("Exec Error cmd:%s" % cmd)
    raise e

isPrintFull = False

def main():
  """
  yumでインストールする際の依存関係を解析するツール
  解析したいパッケージ
   依存パッケージA
    依存パッケージA-1
   依存パッケージB
    依存パッケージB-1
    依存パッケージB-2
     ...
  というような出力を行う。(インデントはスペース)
  yum deplist [パッケージ名]が使える環境であること
  第二引数にfullをつけると、上位ですでに依存すると分かっているパッケージも下位で表示する
  """
  try:
    argv = sys.argv
    package = argv[1]
    if len(argv) >= 3 and "full" == argv[2]:
      global isPrintFull
      isPrintFull = True
      print("*print full*")
    else:
      print("*print summary*")
    
    #依存関係解析
    analyzeDependency(0,package)
  except Exception as e:
    print(e)

if __name__ == '__main__':
  main()

githubにも上げた。
GitHub - y-osaru/dependency_analyzer: yum依存関係解析ツール

実行するとこんな感じになる(クソ長いので一部抜粋)

*print summary*
httpd
 bash.x86_64 4.2.46-34.amzn2
  glibc.x86_64 2.26-57.amzn2
   basesystem.noarch 10.0-7.amzn2.0.1
    filesystem.x86_64 3.2-25.amzn2.0.4
     setup.noarch 2.8.71-10.amzn2.0.1
      system-release.x86_64 1:2-14.amzn2
   glibc.i686 2.26-57.amzn2
    glibc-common.x86_64 2.26-57.amzn2
     libselinux.x86_64 2.5-12.amzn2.0.2
      pcre.x86_64 8.32-17.amzn2.0.2
       libgcc.x86_64 7.3.1-13.amzn2
       libstdc++.x86_64 7.3.1-13.amzn2
      libsepol.x86_64 2.5-8.1.amzn2.0.2
      pcre.i686 8.32-17.amzn2.0.2
       libgcc.i686 7.3.1-13.amzn2
       libstdc++.i686 7.3.1-13.amzn2
     tzdata.noarch 2021e-1.amzn2
    glibc-minimal-langpack.x86_64 2.26-57.amzn2
  ncurses-libs.x86_64 6.0-8.20170212.amzn2.1.3
   ncurses-base.noarch 6.0-8.20170212.amzn2.1.3
 mailcap.noarch 2.1.41-2.amzn2
 httpd.x86_64 2.4.52-1.amzn2
  httpd-filesystem.noarch 2.4.52-1.amzn2
   shadow-utils.x86_64 2:4.1.5.1-24.amzn2.0.2
    audit-libs.x86_64 2.8.1-3.amzn2.1
     audit-libs.i686 2.8.1-3.amzn2.1
      libcap-ng.i686 0.7.5-4.amzn2.0.4
     libcap-ng.x86_64 0.7.5-4.amzn2.0.4
    coreutils.x86_64 8.22-24.amzn2
     info.x86_64 5.1-5.amzn2
      zlib.x86_64 1.2.7-18.amzn2
     gmp.x86_64 1:6.0.0-15.amzn2.0.2
     gmp.i686 1:6.0.0-15.amzn2.0.2

依存関係を調べるコマンドと正規表現を換えれば他のディストリビューションでも使えるかもね。

終わり。