1#
2#
3import shutil
4import re
5import subprocess
6import os
7home=os.getenv("HOME")
8api_version=os.getenv("API_VERSION")
9print "Preparing independant bundle, home="+home+"..., version ) "+str(api_version)
10rootFolder=home+"/Avidemux"+str(api_version)+".app/Contents/Resources"
11libFolder=rootFolder+"/lib"
12binFolder=rootFolder+"/bin"
13frameWorkFolder=rootFolder+"/../Frameworks"
14qtPluginFolder=rootFolder+"/../plugins"
15qts = ['QtCore', 'QtGui', 'QtOpenGL','QtScript','QtWidgets','QtPrintSupport','QtNetwork']
16
17#
18#
19allSymbols=[]
20#
21
22def log(s):
23    #print "Log:<"+str(s)+">"
24    pass
25#
26#
27#
28def getShortName(fl):
29    shortName=re.sub('^.*\/','',fl)
30    return shortName
31#
32# Returns the list of libs as dependencies in /opt (macport)
33#
34def getGlobalDeps(target):
35    cmd = ["/usr/bin/otool","-L", target]
36    log(cmd)
37    q = []
38    cmd = subprocess.Popen(" ".join(cmd), shell=True, stdout=subprocess.PIPE)
39    for line in cmd.stdout:
40       line = re.sub('[ \t\r\n]*', '', line)
41       line = re.sub('\(.*$', '', line)
42       if(not line.startswith('/opt/local') and not line.startswith('/usr/local/opt') and not line.startswith('/usr/local/Cellar/qt5/') and not line.startswith('@rpath')):
43              continue
44       if(":" in line):
45              continue
46       log(line)
47       q.append(line)
48    log(str(q))
49    return q;
50#
51#
52#
53def getGlobalDepsNoQt(target):
54    q= []
55    p = getGlobalDeps(target)
56    for line in p:
57       if not getShortName(line).startswith('Qt'):
58          q.append(line)
59    return q
60#
61def getGlobalDepsQtOnly(target):
62    q= []
63    p = getGlobalDeps(target)
64    for line in p:
65       if getShortName(line).startswith('Qt'):
66          q.append(line)
67    return q
68#
69def getRpathDepsOnly(target):
70    q= []
71    p = getGlobalDeps(target)
72    for line in p:
73       if getShortName(line).startswith('@rpath'):
74          q.append(line)
75    return q
76#
77# Returns the list of libs as dependencies  to local installation folder (
78#
79def getLocalDeps(target):
80    cmd = ["/usr/bin/otool","-L", target]
81    log(cmd)
82    q = []
83    cmd = subprocess.Popen(" ".join(cmd), shell=True, stdout=subprocess.PIPE)
84    for line in cmd.stdout:
85       line = re.sub('[ \t\r\n]*', '', line)
86       line = re.sub('\(.*$', '', line)
87       if(not line.startswith(libFolder)):
88              continue
89       if(":" in line):
90              continue
91       log(line)
92       q.append(line)
93    log(str(q))
94    return q;
95#
96#
97# Copy used library coming from /opt/local
98#
99def copyFiles(folder,libFolder):
100    copied=0
101    log("Copy files"+folder)
102    for dirname, dirnames, filenames in os.walk(folder):
103       for filename in filenames:
104           absPath=os.path.join(dirname, filename)
105           deps=getGlobalDepsNoQt(absPath)
106           for dep in deps:
107               shortName=re.sub('^.*\/','',dep)
108               if(os.path.exists(libFolder+'/'+shortName)):
109                               log(shortName+" already copied")
110               else:
111                   log("Copying"+shortName)
112                   myCopy(dep,libFolder)
113                   copied+=1
114    return copied
115#
116#
117# Copy used library coming from /opt/local
118#
119def copyQtDeps(components,libFolder):
120    copied=0
121    for modul in components:
122        absPath='/usr/local/opt/qt5/lib/'+modul+'.framework/Versions/5/'+modul
123        print("Copy deps for "+modul+" ("+absPath+")")
124        deps=getGlobalDepsNoQt(absPath)
125        for dep in deps:
126                   shortName=re.sub('^.*\/','',dep)
127                   if(os.path.exists(libFolder+'/'+shortName)):
128                               print(shortName+" already copied")
129                   else:
130                       print("Copying:"+shortName)
131                       myCopy(dep,libFolder)
132                       copied+=1
133    # copy plugins deps too
134    copyFiles(qtPluginFolder+'/imageformats',libFolder)
135    return copied
136##
137def changeSymbol(target,oldName,newName):
138        cmd="/usr/bin/install_name_tool -change "+oldName+" "+newName+" "+target
139        log(cmd)
140        subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
141#
142def changeId(target,newId):
143           cmd="/usr/bin/install_name_tool -id "+newId+" "+target
144           log(cmd)
145           subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
146#
147#
148def renameSymbols(libs):
149   for qt in libs:
150      print "Processing "+qt
151      # Change binding
152      for otherQt in allSymbols:
153          newname=re.sub(r'^.*\/',r'@executable_path/../lib/',otherQt)
154          exc="install_name_tool -change "+otherQt+" "+newname+" libToProcess"
155          print(exc)
156#
157#
158#
159def changeGlobalLinkPathForOne(f):
160    deps=getGlobalDepsNoQt(f)
161    for d in deps:
162        shortName=getShortName(d)
163        shortName="@executable_path/../lib/"+shortName
164        changeSymbol(f,d,shortName)
165def changeLocalLinkPathForOne(f):
166    deps=getLocalDeps(f)
167    for d in deps:
168        shortName="@executable_path/../lib/"+re.sub("^.*\/","",d)
169        changeSymbol(f,d,shortName)
170def changeLibLinkPath(folder):
171    for dirname, dirnames, filenames in os.walk(folder):
172       for filename in filenames:
173           absPath=os.path.join(dirname, filename)
174           changeGlobalLinkPathForOne(absPath)
175           changeLocalLinkPathForOne(absPath)
176           changeQtLinkPathForOne(absPath)
177           shortName="@executable_path/../lib/"+re.sub("^.*\/","",absPath)
178           changeId(absPath,shortName)
179#
180def changeQtPlatformLinkPath(folder):
181    for dirname, dirnames, filenames in os.walk(folder):
182       for filename in filenames:
183           absPath=os.path.join(dirname, filename)
184           changeGlobalLinkPathForOne(absPath)
185           changeLocalLinkPathForOne(absPath)
186           changeQtLinkPathForOne(absPath)
187           shortName="@executable_path/../../plugins/platforms/"+re.sub("^.*\/","",absPath)
188           changeId(absPath,shortName)
189def changeQtPluginLinkPath(folder):
190    for dirname, dirnames, filenames in os.walk(folder):
191       for filename in filenames:
192           absPath=os.path.join(dirname, filename)
193           changeGlobalLinkPathForOne(absPath)
194           changeLocalLinkPathForOne(absPath)
195           changeQtLinkPathForOne(absPath)
196           shortName="@executable_path/../../plugins/imageformats/"+re.sub("^.*\/","",absPath)
197           changeId(absPath,shortName)
198def changeBinLinkPath(folder):
199    for dirname, dirnames, filenames in os.walk(folder):
200       for filename in filenames:
201           absPath=os.path.join(dirname, filename)
202           changeGlobalLinkPathForOne(absPath)
203           changeLocalLinkPathForOne(absPath)
204           changeQtLinkPathForOne(absPath)
205           shortName="@executable_path/bin/"+re.sub("^.*\/","",absPath)
206           changeId(absPath,shortName)
207
208def changePluginLinkPath(folder,relFolder):
209    for dirname, dirnames, filenames in os.walk(folder):
210       for filename in filenames:
211           absPath=os.path.join(dirname, filename)
212           changeGlobalLinkPathForOne(absPath)
213           changeQtLinkPathForOne(absPath)
214           shortName="@executable_path/lib/"+relFolder+re.sub("^.*\/","",absPath)
215           changeId(absPath,shortName)
216#
217#
218#
219def myChmod(dst):
220        log("chmod <"+dst+">")
221        cmd="/bin/chmod" + " -R 755  "+dst
222        log("Exec <"+cmd+">")
223        subprocess.call(cmd, shell=True)
224
225#
226def myCopy(src,dst):
227    shutil.copy(src,dst)
228    myChmod(dst)
229
230#
231def changeQtFileSelfLinkPath(fl,modu):
232           shortName="@executable_path/../../Frameworks/"+modu+".framework/Versions/5/"+modu
233           cmd="/usr/bin/install_name_tool -id "+shortName+" "+fl
234           log(cmd)
235           subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
236def changeQtLinkPathForOne(f):
237    deps=getGlobalDepsQtOnly(f)
238    for d in deps:
239        shortName=getShortName(d)
240        shortName="@executable_path/../../Frameworks/"+shortName+".framework/Versions/5/"+shortName
241        changeSymbol(f,d,shortName)
242    deps2=getRpathDepsOnly(f)
243    for d in deps2:
244        shortName2=re.sub('@rpath','@executable_path/../../Frameworks/')
245        changeSymbol(f,d,shortName2)
246
247#
248def myMkDir(target):
249        if(os.path.exists(target)):
250                return
251        os.makedirs(target)
252#
253def myCopyTree(src,dst):
254	log(src+"->"+dst)
255        if(not os.path.exists(src)):
256                return
257        shutil.copytree(src,dst)
258        myChmod(dst)
259def myCopyFile(src,dst):
260        if(not os.path.exists(src)):
261                return
262        myCopy(src,dst)
263##
264def copyQtFiles(targetFolder):
265        myMkDir(targetFolder)
266        for q in qts:
267               print q
268               if(os.path.exists(targetFolder+'/'+q+'.framework')):
269                               log(q+" already copied")
270               else:
271                   log("Copying"+q+' to '+targetFolder)
272                   src='/usr/local/opt/qt5/lib/'+q+'.framework'
273                   dst=targetFolder+'/'+q+'.framework'
274                   myMkDir(dst)
275                   src=src+'/Versions/5/'
276                   dst=dst+'/Versions/'
277                   myMkDir(dst)
278                   dst=dst+'/5/'
279                   myMkDir(dst)
280                   print "Copying "+dst+'Resources'
281                   myCopyTree(src+'Resources',dst+'Resources')
282                   print "Copying "+dst+q
283                   myCopyFile(src+q,dst+q)
284                   changeQtFileSelfLinkPath(dst+q,q)
285                   changeQtLinkPathForOne(dst+q)
286                   changeGlobalLinkPathForOne(dst+q)
287        # Also copy plugins
288        myMkDir(qtPluginFolder)
289	myCopyTree('/usr/local/opt/qt5/plugins/imageformats',qtPluginFolder+'/imageformats')
290	myCopyTree('/usr/local/opt/qt5/plugins/platforms',qtPluginFolder+'/platforms')
291################################################################
292# Step 2 :  Change link name so that they are all executable_path
293#               relative
294#################################################################
295print "Adjusting dependencies"
296changeBinLinkPath(binFolder)
297changeLibLinkPath(libFolder)
298changeQtPluginLinkPath(qtPluginFolder+"/platforms")
299changeQtPluginLinkPath(qtPluginFolder+"/imageformats")
300subFolders=["audioDecoder",    "audioEncoders",   "autoScripts",     "demuxers",        "muxers",          "scriptEngines",   "videoEncoders",   "videoFilters"]
301for s in subFolders:
302        relFolder="ADM_plugins6/"+s
303        changePluginLinkPath(libFolder+"/"+relFolder,relFolder)
304changeQtPlatformLinkPath(binFolder+'/platforms')
305
306
307