#!/usr/bin/env python # -*- coding: utf-8 -*- # Webcamoid, webcam capture application. # Copyright (C) 2017 Gonzalo Exequiel Pedone # # Webcamoid 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 3 of the License, or # (at your option) any later version. # # Webcamoid 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 Webcamoid. If not, see . # # Web-Site: http://webcamoid.github.io/ import math import os import platform import shutil import subprocess # nosec import sys import threading import time from WebcamoidDeployTools import DTDeployBase from WebcamoidDeployTools import DTQt5 from WebcamoidDeployTools import DTBinaryMach class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools): def __init__(self): super().__init__() rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) self.setRootDir(rootDir) self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', self.targetSystem) self.detectQtIFW() self.detectQtIFWVersion() self.programName = 'AkVirtualCamera' self.adminRights = True self.packageConfig = os.path.join(self.buildDir, 'package_info.conf') self.rootInstallDir = os.path.join(self.installDir, 'Applications') self.appBundleDir = os.path.join(self.rootInstallDir, self.programName + '.plugin') self.execPrefixDir = os.path.join(self.appBundleDir, 'Contents') self.binaryInstallDir = os.path.join(self.execPrefixDir, 'MacOS') self.mainBinary = os.path.join(self.binaryInstallDir, self.programName) self.detectMake() self.binarySolver = DTBinaryMach.MachBinaryTools() self.binarySolver.readExcludes(os.name, sys.platform) self.dependencies = [] self.installerConfig = os.path.join(self.installDir, 'installer/config') self.installerPackages = os.path.join(self.installDir, 'installer/packages') self.licenseFile = os.path.join(self.rootDir, 'COPYING') self.installerTargetDir = '@ApplicationsDir@/' + self.programName self.installerScript = os.path.join(self.rootDir, 'ports/deploy/installscript.mac.qs') self.changeLog = os.path.join(self.rootDir, 'ChangeLog') self.outPackage = os.path.join(self.pkgsDir, '{}-{}.dmg'.format(self.programName, self.programVersion())) def prepare(self): self.detectTargetArch() print('Stripping symbols') self.binarySolver.stripSymbols(self.installDir) print('Resetting file permissions') self.binarySolver.resetFilePermissions(self.rootInstallDir, self.binaryInstallDir) print('\nWritting build system information\n') self.writeBuildInfo() print('\nSigning bundle\n') self.signPackage(self.appBundleDir) @staticmethod def sysInfo(): process = subprocess.Popen(['sw_vers'], # nosec stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, _ = process.communicate() return stdout.decode(sys.getdefaultencoding()).strip() def writeBuildInfo(self): try: os.makedirs(self.pkgsDir) except: pass resourcesDir = os.path.join(self.execPrefixDir, 'Resources') try: os.makedirs(resourcesDir) except: pass depsInfoFile = os.path.join(resourcesDir, 'build-info.txt') # Write repository info. with open(depsInfoFile, 'w') as f: commitHash = self.gitCommitHash(self.rootDir) if len(commitHash) < 1: commitHash = 'Unknown' print(' Commit hash: ' + commitHash) f.write('Commit hash: ' + commitHash + '\n') buildLogUrl = '' if 'TRAVIS_BUILD_WEB_URL' in os.environ: buildLogUrl = os.environ['TRAVIS_BUILD_WEB_URL'] elif 'APPVEYOR_ACCOUNT_NAME' in os.environ and 'APPVEYOR_PROJECT_NAME' in os.environ and 'APPVEYOR_JOB_ID' in os.environ: buildLogUrl = 'https://ci.appveyor.com/project/{}/{}/build/job/{}'.format(os.environ['APPVEYOR_ACCOUNT_NAME'], os.environ['APPVEYOR_PROJECT_SLUG'], os.environ['APPVEYOR_JOB_ID']) if len(buildLogUrl) > 0: print(' Build log URL: ' + buildLogUrl) f.write('Build log URL: ' + buildLogUrl + '\n') print() f.write('\n') # Write host info. info = self.sysInfo() with open(depsInfoFile, 'a') as f: for line in info.split('\n'): if len(line) > 0: print(' ' + line) f.write(line + '\n') print() f.write('\n') @staticmethod def hrSize(size): i = int(math.log(size) // math.log(1024)) if i < 1: return '{} B'.format(size) units = ['KiB', 'MiB', 'GiB', 'TiB'] sizeKiB = size / (1024 ** i) return '{:.2f} {}'.format(sizeKiB, units[i - 1]) def printPackageInfo(self, path): if os.path.exists(path): print(' ', os.path.basename(path), self.hrSize(os.path.getsize(path))) print(' sha256sum:', Deploy.sha256sum(path)) else: print(' ', os.path.basename(path), 'FAILED') @staticmethod def dirSize(path): size = 0 for root, _, files in os.walk(path): for f in files: fpath = os.path.join(root, f) if not os.path.islink(fpath): size += os.path.getsize(fpath) return size def signPackage(self, package): process = subprocess.Popen(['codesign', # nosec '--force', '--sign', '-', package], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.communicate() def createAppInstaller(self, mutex): packagePath = self.createInstaller() if not packagePath: return mutex.acquire() print('Created installable package:') self.printPackageInfo(self.outPackage) mutex.release() def package(self): mutex = threading.Lock() threads = [] packagingTools = [] if self.qtIFW != '': threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,))) packagingTools += ['Qt Installer Framework'] if len(packagingTools) > 0: print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) for thread in threads: thread.start() for thread in threads: thread.join()