diff --git a/dist/codesign.py b/dist/codesign.py index c8f28e7f3..7c111fdb5 100755 --- a/dist/codesign.py +++ b/dist/codesign.py @@ -6,13 +6,15 @@ import re import subprocess import sys -def SignPath(path, developer_id): +def SignPath(path, developer_id, deep=True): args = [ 'codesign', '--preserve-metadata=identifier,entitlements,resource-rules,requirements', '-s', developer_id, '-fv', path ] + if deep: + args.append('--deep') subprocess.check_call(args) def main(): @@ -34,7 +36,13 @@ def main(): elif re.match(r'(clementine-spotifyblob|clementine-tagreader|gst-plugin-scanner)', file): SignPath(os.path.join(root, file), developer_id) - SignPath(app_bundle, developer_id) + SignPath(app_bundle, developer_id, deep=False) + + # Verify the signatures are valid. + subprocess.check_call([ + 'codesign', '--verify', '--verbose=4', app_bundle]) + subprocess.check_call([ + 'spctl', '--assess', '--verbose=4', app_bundle]) if __name__ == '__main__': diff --git a/dist/macdeploy.py b/dist/macdeploy.py index ff5521e15..872c2a076 100755 --- a/dist/macdeploy.py +++ b/dist/macdeploy.py @@ -146,6 +146,10 @@ class CouldNotFindGioModuleError(Error): pass +class CouldNotParseFrameworkNameError(Error): + pass + + if len(sys.argv) < 2: print 'Usage: %s ' % sys.argv[0] @@ -163,8 +167,8 @@ commands.append(['mkdir', '-p', resources_dir]) plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns') binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name) -fixed_libraries = [] -fixed_frameworks = [] +fixed_libraries = set() +fixed_frameworks = set() def GetBrokenLibraries(binary): output = subprocess.Popen(['otool', '-L', binary], stdout=subprocess.PIPE).communicate()[0] @@ -221,10 +225,10 @@ def FixAllLibraries(broken_libs): FixLibrary(lib) def FixFramework(path): - if path in fixed_libraries: + if path in fixed_frameworks: return else: - fixed_libraries.append(path) + fixed_frameworks.add(path) abs_path = FindFramework(path) broken_libs = GetBrokenLibraries(abs_path) FixAllLibraries(broken_libs) @@ -241,7 +245,7 @@ def FixLibrary(path): if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None: return else: - fixed_libraries.append(path) + fixed_libraries.add(path) abs_path = FindLibrary(path) broken_libs = GetBrokenLibraries(abs_path) FixAllLibraries(broken_libs) @@ -287,24 +291,60 @@ def CopyPlugin(path, subdir): LOGGER.info("Copying plugin '%s'", path) return new_path -def CopyFramework(path): - parts = path.split(os.sep) - for i, part in enumerate(parts): - if re.match(r'\w+\.framework', part): - full_path = os.path.join(frameworks_dir, *parts[i:-1]) - break - args = ['mkdir', '-p', full_path] - commands.append(args) - args = ['ditto', '--arch=x86_64', path, full_path] - commands.append(args) +def CopyFramework(src_binary): + while os.path.islink(src_binary): + src_binary = os.path.realpath(src_binary) + + m = re.match(r'(.*/([^/]+)\.framework)/Versions/([^/]+)/.*', src_binary) + if not m: + raise CouldNotParseFrameworkNameError(src_binary) - menu_nib = os.path.join(os.path.split(path)[0], 'Resources', 'qt_menu.nib') + src_base = m.group(1) + name = m.group(2) + version = m.group(3) + + LOGGER.info("Copying framework %s version %s", name, version) + + dest_base = os.path.join(frameworks_dir, '%s.framework' % name) + dest_dir = os.path.join(dest_base, 'Versions', version) + dest_binary = os.path.join(dest_dir, name) + + commands.append(['mkdir', '-p', dest_dir]) + commands.append(['ditto', '--arch=x86_64', src_binary, dest_binary]) + + # Copy special files from various places: + # QtCore has Resources/qt_menu.nib (copy to app's Resources) + # Sparkle has Resources/* + # Qt* have Resources/Info.plist + resources_src = os.path.join(src_base, 'Resources') + menu_nib = os.path.join(resources_src, 'qt_menu.nib') if os.path.exists(menu_nib): - args = ['cp', '-r', menu_nib, resources_dir] - commands.append(args) + LOGGER.info("Copying qt_menu.nib '%s'", menu_nib) + commands.append(['cp', '-r', menu_nib, resources_dir]) + elif os.path.exists(resources_src): + LOGGER.info("Copying resources dir '%s'", resources_src) + commands.append(['cp', '-r', resources_src, dest_dir]) - LOGGER.info("Copying framework '%s'", path) - return os.path.join(full_path, parts[-1]) + info_plist = os.path.join(src_base, 'Contents', 'Info.plist') + if os.path.exists(info_plist): + LOGGER.info("Copying special file '%s'", info_plist) + resources_dest = os.path.join(dest_dir, 'Resources') + commands.append(['mkdir', resources_dest]) + commands.append(['cp', '-r', info_plist, resources_dest]) + + # Create symlinks in the Framework to make it look like + # https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html + commands.append(['ln', '-sf', + 'Versions/Current/%s' % name, + os.path.join(dest_base, name)]) + commands.append(['ln', '-sf', + 'Versions/Current/Resources', + os.path.join(dest_base, 'Resources')]) + commands.append(['ln', '-sf', + version, + os.path.join(dest_base, 'Versions/Current')]) + + return dest_binary def FixId(path, library_name): id = '@executable_path/../Frameworks/%s' % library_name diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0cb379451..648d229ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1417,28 +1417,6 @@ if (APPLE) install(DIRECTORY "${QT_QTGUI_LIBRARY_RELEASE}/Versions/Current/Resources/" DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources") - if (HAVE_SPARKLE) - install(DIRECTORY "${SPARKLE}/Versions/Current/Resources" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/Sparkle.framework") - endif (HAVE_SPARKLE) - - foreach (plist_destination Versions/4/Resources Resources) - install(FILES "${QT_QTCORE_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtCore.framework/${plist_destination}") - install(FILES "${QT_QTGUI_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtGui.framework/${plist_destination}") - install(FILES "${QT_QTNETWORK_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtNetwork.framework/${plist_destination}") - install(FILES "${QT_QTOPENGL_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtOpenGL.framework/${plist_destination}") - install(FILES "${QT_QTSQL_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSql.framework/${plist_destination}") - install(FILES "${QT_QTSVG_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSvg.framework/${plist_destination}") - install(FILES "${QT_QTXML_LIBRARY_RELEASE}/Contents/Info.plist" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtXml.framework/${plist_destination}") - endforeach() - if (HAVE_BREAKPAD) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/google-breakpad/client/mac/build/Release/Breakpad.framework