mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-27 17:37:36 +03:00
d0d5b2b4ee
Qt now only build it if the system library is available since libmng isn't active enough to make its security reliable enough. We don't use that image format ourselves anyway.
349 lines
11 KiB
Python
Executable file
349 lines
11 KiB
Python
Executable file
#!/usr/bin/python
|
|
# This file is part of ownCloud.
|
|
# It was inspired in large part by the macdeploy script in Clementine
|
|
# and Tomahawk
|
|
#
|
|
# ownCloud 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.
|
|
#
|
|
# ownCLoud 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 ownCloud. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import commands
|
|
import sys
|
|
from glob import glob
|
|
|
|
def QueryQMake(attrib):
|
|
return subprocess.check_output([qmake_path, '-query', attrib]).rstrip('\n')
|
|
|
|
FRAMEWORK_SEARCH_PATH=[
|
|
'/Library/Frameworks',
|
|
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
|
]
|
|
|
|
LIBRARY_SEARCH_PATH=['/usr/local/lib', '.']
|
|
|
|
QT_PLUGINS = [
|
|
'sqldrivers/libqsqlite.dylib',
|
|
'platforms/libqcocoa.dylib',
|
|
'imageformats/libqgif.dylib',
|
|
'imageformats/libqico.dylib',
|
|
'imageformats/libqjpeg.dylib',
|
|
'imageformats/libqsvg.dylib',
|
|
]
|
|
|
|
QT_PLUGINS_SEARCH_PATH=[
|
|
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
|
'/usr/local/Cellar/qt/5.2.1/plugins',
|
|
]
|
|
|
|
|
|
class Error(Exception):
|
|
pass
|
|
|
|
|
|
class CouldNotFindQtPluginErrorFindFrameworkError(Error):
|
|
pass
|
|
|
|
|
|
class InstallNameToolError(Error):
|
|
pass
|
|
|
|
|
|
class CouldNotFindQtPluginError(Error):
|
|
pass
|
|
|
|
|
|
class CouldNotFindScriptPluginError(Error):
|
|
pass
|
|
|
|
class CouldNotFindFrameworkError(Error):
|
|
pass
|
|
|
|
if len(sys.argv) < 3:
|
|
print 'Usage: %s <bundle.app> <path-to-qmake>' % sys.argv[0]
|
|
exit()
|
|
|
|
def is_exe(fpath):
|
|
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
|
|
|
bundle_dir = sys.argv[1]
|
|
qmake_path = sys.argv[2]
|
|
|
|
bundle_name = os.path.basename(bundle_dir).split('.')[0]
|
|
|
|
commands = []
|
|
|
|
binary_dir = os.path.join(bundle_dir, 'Contents', 'MacOS')
|
|
frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
|
|
commands.append(['mkdir', '-p', frameworks_dir])
|
|
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
|
|
commands.append(['mkdir', '-p', resources_dir])
|
|
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
|
binaries = [i for i in glob(os.path.join(bundle_dir, 'Contents', 'MacOS', "*")) if is_exe(i)];
|
|
|
|
|
|
fixed_libraries = []
|
|
fixed_frameworks = []
|
|
|
|
def WriteQtConf():
|
|
print "Writing qt.conf..."
|
|
with open(os.path.join(resources_dir, 'qt.conf'), 'w') as f:
|
|
f.write("[Paths]\nPlugins = PlugIns\n");
|
|
f.close()
|
|
|
|
def GetBrokenLibraries(binary):
|
|
#print "Checking libs for binary: %s" % binary
|
|
output = subprocess.Popen(['otool', '-L', binary], stdout=subprocess.PIPE).communicate()[0]
|
|
broken_libs = {
|
|
'frameworks': [],
|
|
'libs': []}
|
|
for line in [x.split(' ')[0].lstrip() for x in output.split('\n')[1:]]:
|
|
#print "Checking line: %s" % line
|
|
if not line: # skip empty lines
|
|
continue
|
|
if os.path.basename(binary) == os.path.basename(line):
|
|
#print "mnope %s-%s" % (os.path.basename(binary), os.path.basename(line))
|
|
continue
|
|
if re.match(r'^\s*/System/', line):
|
|
continue # System framework
|
|
elif re.match(r'^\s*/usr/lib/', line):
|
|
#print "unix style system lib"
|
|
continue # unix style system library
|
|
elif re.match(r'Breakpad', line):
|
|
continue # Manually added by cmake.
|
|
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
|
|
# Potentially already fixed library
|
|
if '.framework' in line:
|
|
relative_path = os.path.join(*line.split('/')[3:])
|
|
if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
|
|
broken_libs['frameworks'].append(relative_path)
|
|
else:
|
|
relative_path = os.path.join(*line.split('/')[1:])
|
|
#print "RELPATH %s %s" % (relative_path, os.path.join(binary_dir, relative_path))
|
|
if not os.path.exists(os.path.join(binary_dir, relative_path)):
|
|
broken_libs['libs'].append(relative_path)
|
|
elif re.search(r'\w+\.framework', line):
|
|
broken_libs['frameworks'].append(line)
|
|
else:
|
|
broken_libs['libs'].append(line)
|
|
|
|
return broken_libs
|
|
|
|
def FindFramework(path):
|
|
search_pathes = FRAMEWORK_SEARCH_PATH
|
|
search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
|
|
for search_path in search_pathes:
|
|
# The following two lines are needed for a custom built Qt from version 5.5 on, possibly not for the one from the Qt SDK.
|
|
# Looks like the upstream macdeployqt also had an issue there https://bugreports.qt.io/browse/QTBUG-47868
|
|
if path.find( "\@rpath/"):
|
|
path = path.replace("@rpath/", "")
|
|
abs_path = os.path.join(search_path, path)
|
|
if os.path.exists(abs_path):
|
|
return abs_path
|
|
|
|
raise CouldNotFindFrameworkError(path)
|
|
|
|
def FindLibrary(path):
|
|
if os.path.exists(path):
|
|
return path
|
|
search_pathes = LIBRARY_SEARCH_PATH
|
|
search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
|
|
for search_path in search_pathes:
|
|
abs_path = os.path.join(search_path, path)
|
|
if os.path.exists(abs_path):
|
|
return abs_path
|
|
else: # try harder---look for lib name in library folders
|
|
newpath = os.path.join(search_path,os.path.basename(path))
|
|
if os.path.exists(newpath):
|
|
return newpath
|
|
|
|
return ""
|
|
#raise CouldNotFindFrameworkError(path)
|
|
|
|
def FixAllLibraries(broken_libs):
|
|
for framework in broken_libs['frameworks']:
|
|
FixFramework(framework)
|
|
for lib in broken_libs['libs']:
|
|
FixLibrary(lib)
|
|
|
|
def FixFramework(path):
|
|
if path in fixed_libraries:
|
|
return
|
|
else:
|
|
fixed_libraries.append(path)
|
|
abs_path = FindFramework(path)
|
|
broken_libs = GetBrokenLibraries(abs_path)
|
|
FixAllLibraries(broken_libs)
|
|
|
|
new_path = CopyFramework(abs_path)
|
|
id = os.sep.join(new_path.split(os.sep)[3:])
|
|
FixFrameworkId(new_path, id)
|
|
for framework in broken_libs['frameworks']:
|
|
FixFrameworkInstallPath(framework, new_path)
|
|
for library in broken_libs['libs']:
|
|
FixLibraryInstallPath(library, new_path)
|
|
|
|
def FixLibrary(path):
|
|
if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None:
|
|
return
|
|
else:
|
|
fixed_libraries.append(path)
|
|
abs_path = FindLibrary(path)
|
|
if abs_path == "":
|
|
print "Could not resolve %s, not fixing!" % path
|
|
return
|
|
broken_libs = GetBrokenLibraries(abs_path)
|
|
FixAllLibraries(broken_libs)
|
|
|
|
new_path = CopyLibrary(abs_path)
|
|
FixLibraryId(new_path)
|
|
for framework in broken_libs['frameworks']:
|
|
FixFrameworkInstallPath(framework, new_path)
|
|
for library in broken_libs['libs']:
|
|
FixLibraryInstallPath(library, new_path)
|
|
|
|
def FixPlugin(abs_path, subdir):
|
|
broken_libs = GetBrokenLibraries(abs_path)
|
|
FixAllLibraries(broken_libs)
|
|
|
|
new_path = CopyPlugin(abs_path, subdir)
|
|
for framework in broken_libs['frameworks']:
|
|
FixFrameworkInstallPath(framework, new_path)
|
|
for library in broken_libs['libs']:
|
|
FixLibraryInstallPath(library, new_path)
|
|
|
|
def FixBinary(path):
|
|
broken_libs = GetBrokenLibraries(path)
|
|
FixAllLibraries(broken_libs)
|
|
for framework in broken_libs['frameworks']:
|
|
FixFrameworkInstallPath(framework, path)
|
|
for library in broken_libs['libs']:
|
|
FixLibraryInstallPath(library, path)
|
|
|
|
def CopyLibrary(path):
|
|
new_path = os.path.join(binary_dir, os.path.basename(path))
|
|
args = ['ditto', '--arch=x86_64', path, new_path]
|
|
commands.append(args)
|
|
args = ['chmod', 'u+w', new_path]
|
|
commands.append(args)
|
|
return new_path
|
|
|
|
def CopyPlugin(path, subdir):
|
|
new_path = os.path.join(plugins_dir, subdir, os.path.basename(path))
|
|
args = ['mkdir', '-p', os.path.dirname(new_path)]
|
|
commands.append(args)
|
|
args = ['ditto', '--arch=x86_64', path, new_path]
|
|
commands.append(args)
|
|
args = ['chmod', 'u+w', new_path]
|
|
commands.append(args)
|
|
return new_path
|
|
|
|
def CopyFramework(source_dylib):
|
|
parts = source_dylib.split(os.sep)
|
|
print "CopyFramework:", source_dylib
|
|
for i, part in enumerate(parts):
|
|
matchObj = re.match(r'(\w+\.framework)', part)
|
|
if matchObj:
|
|
framework = matchObj.group(1)
|
|
dylib_name = parts[-1]
|
|
source_path = os.path.join('/', *parts[:i+1])
|
|
dest_path = os.path.join(frameworks_dir, framework)
|
|
dest_dylib_path = os.path.join(frameworks_dir, *parts[i:-1])
|
|
break
|
|
if os.path.exists(dest_path):
|
|
print dest_path, "already exists, skipping copy..."
|
|
return os.path.join(dest_dylib_path, dylib_name)
|
|
|
|
args = ['mkdir', '-p', dest_dylib_path]
|
|
commands.append(args)
|
|
args = ['ditto', '--arch=x86_64', source_dylib, dest_dylib_path]
|
|
commands.append(args)
|
|
args = ['chmod', 'u+w', os.path.join(dest_dylib_path, parts[-1])]
|
|
commands.append(args)
|
|
args = ['ln', '-s', '5', os.path.join(dest_path, 'Versions', 'Current')]
|
|
commands.append(args)
|
|
args = ['ln', '-s', os.path.join('Versions', 'Current', dylib_name), os.path.join(dest_path, dylib_name)]
|
|
commands.append(args)
|
|
args = ['ln', '-s', os.path.join('Versions', 'Current', 'Resources'), os.path.join(dest_path, 'Resources')]
|
|
commands.append(args)
|
|
args = ['cp', '-r', os.path.join(source_path, 'Versions', '5', 'Resources'), os.path.join(dest_path, 'Versions', '5')]
|
|
commands.append(args)
|
|
|
|
return os.path.join(dest_dylib_path, dylib_name)
|
|
|
|
def FixId(path, library_name):
|
|
id = '@executable_path/../Frameworks/%s' % library_name
|
|
args = ['install_name_tool', '-id', id, path]
|
|
commands.append(args)
|
|
|
|
def FixLibraryId(path):
|
|
library_name = os.path.basename(path)
|
|
FixId(path, library_name)
|
|
|
|
def FixFrameworkId(path, id):
|
|
FixId(path, id)
|
|
|
|
def FixInstallPath(library_path, library, new_path):
|
|
args = ['install_name_tool', '-change', library_path, new_path, library]
|
|
commands.append(args)
|
|
|
|
def FindSystemLibrary(library_name):
|
|
for path in ['/lib', '/usr/lib']:
|
|
full_path = os.path.join(path, library_name)
|
|
if os.path.exists(full_path):
|
|
return full_path
|
|
return None
|
|
|
|
def FixLibraryInstallPath(library_path, library):
|
|
system_library = FindSystemLibrary(os.path.basename(library_path))
|
|
if system_library is None:
|
|
new_path = '@executable_path/../MacOS/%s' % os.path.basename(library_path)
|
|
FixInstallPath(library_path, library, new_path)
|
|
else:
|
|
FixInstallPath(library_path, library, system_library)
|
|
|
|
def FixFrameworkInstallPath(library_path, library):
|
|
parts = library_path.split(os.sep)
|
|
for i, part in enumerate(parts):
|
|
if re.match(r'\w+\.framework', part):
|
|
full_path = os.path.join(*parts[i:])
|
|
break
|
|
new_path = '@executable_path/../Frameworks/%s' % full_path
|
|
FixInstallPath(library_path, library, new_path)
|
|
|
|
def FindQtPlugin(name):
|
|
search_path = QT_PLUGINS_SEARCH_PATH
|
|
search_path.insert(0, QueryQMake('QT_INSTALL_PLUGINS'))
|
|
for path in search_path:
|
|
if os.path.exists(path):
|
|
if os.path.exists(os.path.join(path, name)):
|
|
return os.path.join(path, name)
|
|
raise CouldNotFindQtPluginError(name)
|
|
|
|
for binary in binaries:
|
|
FixBinary(binary)
|
|
|
|
for plugin in QT_PLUGINS:
|
|
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
|
|
|
if len(sys.argv) <= 2:
|
|
print 'Will run %d commands:' % len(commands)
|
|
for command in commands:
|
|
print ' '.join(command)
|
|
|
|
for command in commands:
|
|
p = subprocess.Popen(command)
|
|
os.waitpid(p.pid, 0)
|
|
|
|
WriteQtConf()
|