Skip to content

Instantly share code, notes, and snippets.

@kushaldas
Created May 13, 2020 11:16
Show Gist options
  • Save kushaldas/d1e639d58eb86191d2485de0c6a59a0a to your computer and use it in GitHub Desktop.
Save kushaldas/d1e639d58eb86191d2485de0c6a59a0a to your computer and use it in GitHub Desktop.
Script to find the library dependencies from the PyQt5 wheel
#!/usr/bin/env python3
import os
import json
import subprocess
from pprint import pprint
from collections import defaultdict
dirname = "./venv/lib/python3.7/site-packages/PyQt5/"
alldetails = {}
reverse_deps = defaultdict(list)
deps = {}
missing = set()
filepath_missing = {}
def travarse_dir(path):
"Travarse a given directory"
for dirs, subdirs, files in os.walk(path):
for filename in files:
if filename.endswith(".so"):
yield os.path.join(dirs, filename)
def ldd(filepath):
"""Finds the library dependencies of a given library .so file.
"""
global alldetails
text = subprocess.check_output(["ldd", filepath]).decode("utf-8")
missing_deps = []
deps = []
for line in text.split("\n"):
line = line.strip()
line = line.replace("\t", " ")
words = line.split(" ")
# proper files will have 4 parts
if len(words) == 1:
continue
if len(words) != 4:
missing_deps.append(words[0])
continue
# now properly parse
# system files will not have dirname
if words[2].find("venv") == -1:
deps.append(words[2])
else:
print(f"Dependency found in the virtualenv {words[2]}")
result = {"missing": list(set(missing_deps)), "deps": list(set(deps))}
alldetails[os.path.basename(filepath)] = result
return result
def deb_package_name(filepath):
"returns the debian package name for a given file"
global reverse_deps
global missing
# first check cache
if filepath in deps:
print("Found it cache.")
return deps[filepath]
if filepath in missing:
print("Found it missing cache.")
return ""
text = ""
real = os.path.basename(filepath)
try:
text = (
subprocess.check_output(["apt-file", "search", filepath])
.decode("utf-8")
.strip()
)
for line in text.split("\n"):
words = line.split(":")
found = os.path.basename(words[1].strip())
if real != found:
continue
name = words[0]
# Store in the global variables
reverse_deps[name].append(filepath)
deps[filepath] = name
print("Executed command to find")
return name
except subprocess.CalledProcessError:
print("Missing the above file.")
missing.add(filepath)
return ""
raise Exception("Should not reach")
return ""
def main():
count = 0
packages = set()
for name in travarse_dir(dirname):
# This variable stores for every .so file, which all are the missing dependency .so file.
local_missing = []
result = ldd(name)
print(f"Processing {name}\n")
for dep in result["deps"]:
print(f"Finding package name for {dep}", end=" ")
package_name = deb_package_name(dep)
if package_name:
packages.add(package_name)
else:
local_missing.append(dep)
filepath_missing[name] = local_missing
pprint(packages)
print("The following files are missing:")
pprint(missing)
data = {
"alldetails": alldetails,
"missing": list(missing),
"filepath_missing": filepath_missing,
"deps": deps,
"reverse_deps": reverse_deps,
}
with open("libsearresult.josn", "w") as fobj:
json.dump(data, fp=fobj)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment