-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathJTPcollectDependencies.py
113 lines (79 loc) · 3.89 KB
/
JTPcollectDependencies.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""JTPcollectDependencies"""
import sys
import re
from subprocess import check_output
import os
from os import path
from subprocess import call
import logging
import shutil
class JTPcollectDependencies:
def collectDependencies(self, args):
# Move libary into target directory, checking if it is a exists or is a symlink.
fileMoved = self.moveLibrary(args.source, args.destination)
# Read dendencies into a list, skip if the file has already been moved and therefore parsed
if fileMoved != 1:
currentLib = path.basename(args.source)
logging.debug('Parsing dependencies for ' + currentLib)
# Skip symlinks
if not path.islink(args.source):
dependencies = check_output(['otool', '-L', '-X', args.source])
for libPath in dependencies.split('\t'):
# If dependency starts @rpath, call collectDependancies() to collect it.
libPath = libPath.rstrip()
libNameMatch = re.match('@rpath/(.+?\.dylib)\W.+', libPath, flags=0)
if libNameMatch:
libName = libNameMatch.group(1)
# Skip the self reference
if currentLib != libName:
args2 = args
sourcePath = path.split(args.source)
args2.source = path.join(sourcePath[0], libName)
self.collectDependencies(args2)
elif fileMoved == -1:
logging.error('Error encountered moving: ' + args.source)
# Return when done.
def moveLibrary(self, source, destination):
"""Move dylibs, checking for symlinks, returns, 0 file moved ok, 1, file existed already, -1 error."""
# Check the file is not already present.
fileName = path.basename(source)
fullDest = path.join(destination, fileName)
# Skip files already present at the destination.
if path.isfile(fullDest):
logging.debug(fileName + ' already present in destination, skipping.')
return 1
# Check if we have a symlink.
elif path.islink(source):
# If so, copy the target and relink.
linkDestination = path.realpath(source)
linkDestinationName = path.basename(linkDestination)
# Move the source
self.moveLibrary(linkDestination, destination)
# Relink the reference.
linkFile = path.join(destination, fileName)
os.symlink(linkDestinationName, linkFile)
logging.debug(fileName + ' relinked to ' + linkDestination + '.')
return 0
# Copy normaly
else:
destinationFile = path.join(destination, fileName)
shutil.copy(source, destinationFile)
logging.debug(fileName + ' copied to destination.')
return 0
# Should never fall through to here.
return -1
def main():
import sys
import argparse
parser = argparse.ArgumentParser(description='Collect all the runtime (@rpath/...) dylibs a specified dylib is dependent on.')
parser.add_argument("-v", "--verbose", help="increase output verbosity", action="store_true")
parser.add_argument('source', type=str, help='Path to the dylib to parse.')
parser.add_argument('destination', type=str, help='Path to a directory to save the collected dylibs into.')
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
logging.debug('Parsing dependencies, starting with: ' + args.source + '\nCopying to: ' + args.destination)
"""Get working."""
JTPcollectDependencies().collectDependencies(args)
if __name__=='__main__':
main()