#!/usr/bin/env python # # chkdep # # Copyright (c) 2007, 2010 by Miklos Vajna # Copyright (c) 2007 by Marcus Habermehl # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, # USA. # import subprocess, tempfile, shutil, os, stat, re, pacman, getopt, sys from modulefinder import ModuleFinder def usage(): os.system("man chkdep") getdeps_deps = [] def getdeps(root): i = pacman.db_getpkgcache(db) while i: pkg = pacman.void_to_PM_PKG(pacman.list_getdata(i)) pkgname = pacman.void_to_char(pacman.pkg_getinfo(pkg, pacman.PKG_NAME)) if pkgname == root: j = pacman.void_to_PM_LIST(pacman.pkg_getinfo(pkg, pacman.PKG_DEPENDS)) while j: dep = pacman.void_to_char(pacman.list_getdata(j)).split("<")[0].split(">")[0].split("=")[0] if dep not in getdeps_deps: getdeps_deps.append(dep) getdeps(dep) j = pacman.list_next(j) break i = pacman.list_next(i) return getdeps_deps def rmdupdeps(deps): depdeps = [] newdeps = [] for i in deps: if i not in ignorepkgs: depdeps.extend(getdeps(i)) for i in deps: if i not in depdeps and i not in ignorepkgs: newdeps.append(i) elif i in depdeps and trace: print "Ignoring %s as it is already a dependency of some other dependency." % i elif i in ignorepkgs and trace: print "Ignoring %s as requested." % i return newdeps def detect_owner(lib): global quiet if not len(lib): return if lib.find(fpmroot) == 0: return pkg = pacman.void_to_PM_PKG(pacman.list_getdata(pacman.pkg_getowners(lib))) owner = pacman.void_to_char(pacman.pkg_getinfo(pkg, pacman.PKG_NAME)) if not owner and not quiet: print >>sys.stderr, "WARNING: No package found containing %s!" % lib elif owner not in deps: if trace: print "%s is an owner for %s" % (owner, lib) deps.append(owner) class Checks: def python(self, file): ftype = os.popen("file -b %s" % file).read().rstrip() if not "python script" in ftype and not file.endswith(".py"): return libs = [] modules = [] regex1 = r"import ([a-zA-Z0-9_\.]*)" regex2 = r"from ([a-zA-Z0-9_\.]*) import" fd = open(file, "r") for line in fd.readlines(): module = str() if re.match(regex1, line): module = re.match(regex1, line).groups()[0].rstrip() elif re.match(regex2, line): module = re.match(regex2, line).groups()[0].rstrip() else: continue if not module: continue if not module in libs: modules.append(module) fd.close() for module in modules: mod_file = str() mod_repl = module.replace(".", "/") for path in sys.path: if os.path.isfile("%s/%s.py" % (path, mod_repl)): mod_file = "%s/%s.py" % (path, mod_repl) break elif os.path.isfile("%s/%s.so" % (path, mod_repl)): mod_file = "%s/%s.so" % (path, mod_repl) break elif os.path.isfile("%s/%s/__init__.py" % (path, mod_repl)): mod_file = "%s/%s/__init__.py" % (path, mod_repl) break libs.append(mod_file) return libs def elf(self, file): try: if not os.stat(file)[stat.ST_MODE] & stat.S_IXUSR: return except OSError: return libs = [] sock = os.popen("ldd %s 2>%s" % (file, os.devnull)) while True: i = sock.readline() if not i: break if i.find("=>") == -1: continue lib = re.sub(r".* => (.*) \(.*", r"\1", i.strip()) if ' ' in lib: # not all the deps are installed lib = lib.split(' ')[0] if len(lib): if trace: print "'%s' links to '%s'." % (file, lib) libs.append(lib) sock.close() return libs def mono(self, file): dlls = [] ret = [] sock = os.popen("monodis --assemblyref %s" % file) while True: i = sock.readline() if not i: break if i.find("Name=") == -1: continue dll = i.strip().split('Name=')[1] if dll not in dlls: dlls.append(dll) sock.close() for i in dlls: sock = os.popen('MONO_LOG_LEVEL="debug" mono --aot %s' % i) while True: j = sock.readline() if not j: break if j.find(i) != -1: break sock.close() ret.append((re.sub(r".*'(.*)'.*", r"\1", j.strip()))) return ret def perl(self, file): mods = [] ret = [] sock = open(file) while True: modules = [] i = sock.readline() if not i: break if not re.match(r"^use [^ ]+::", i): continue lib = re.sub(r"^use ([^ ]+::[^ ]+)( |;).*", r"\1", i.strip()) mods.append(lib) sock.close() for i in mods: sock = os.popen("perldoc -l %s" % i) ret.append(sock.readline().strip()) sock.close() return ret checks = Checks() pacman.initialize("/") db = pacman.db_register("local") ignorepkgs = [] deps = [] dir = None method="elf" pkg = None quiet = False trace = False try: opts, args = getopt.getopt(sys.argv[1:], "d:p:qn:m:tvi", ["dir=", "package=", "quiet", "ignore=", "method=", "trace", "version"]) except getopt.GetoptError: usage() sys.exit(1) for opt, arg in opts: if opt in ("-d", "--dir"): dir = arg if opt in ("-p", "--package"): pkg = arg if opt in ("-q", "--quiet"): quiet = True if opt in ("-m", "--method"): method = arg if opt in ("-n", "--name"): ignorepkgs.append(arg) if opt in ("-t", "--trace"): trace = True if opt in ("-v", "--version"): print "chkdep %s" % __version__ sys.exit(0) if not dir and not pkg: usage() sys.exit(1) checker = getattr(checks, method) if "FAKEROOTKEY" in os.environ.keys(): ignorepkgs.append("fakeroot") if pkg: fpmroot = tempfile.mkdtemp() cwd = os.getcwd() os.chdir(fpmroot) if subprocess.call(["bsdtar", "xf", os.path.join(cwd, pkg)]) != 0: raise Exception("bsdtar failed") os.chdir(cwd) if dir: fpmroot = dir depfiles = [] for root, dirs, files in os.walk(fpmroot): for file in files: ret = checker(os.path.join(root, file)) if ret: for i in ret: if i not in depfiles: if trace: print "Found %s as a new dependency file." % i depfiles.append(i) for i in depfiles: detect_owner(i) if pkg: shutil.rmtree(fpmroot) if trace: print "Dependencies before dependency cleanup: depends=('" + "' '".join(deps) + "')" deps = rmdupdeps(deps) print "depends=('" + "' '".join(deps) + "')"