Fixed Mac installer.
This commit is contained in:
parent
3a2d692aa3
commit
be30112a27
12 changed files with 117 additions and 439 deletions
|
@ -94,9 +94,9 @@ script:
|
||||||
- chmod +x ports/ci/travis/build.sh
|
- chmod +x ports/ci/travis/build.sh
|
||||||
- ports/ci/travis/build.sh
|
- ports/ci/travis/build.sh
|
||||||
|
|
||||||
#after_success:
|
after_success:
|
||||||
# - chmod +x ports/ci/travis/deploy.sh
|
- chmod +x ports/ci/travis/deploy.sh
|
||||||
# - ports/ci/travis/deploy.sh
|
- ports/ci/travis/deploy.sh
|
||||||
# - chmod +x ports/ci/travis/upload.sh
|
# - chmod +x ports/ci/travis/upload.sh
|
||||||
# - ports/ci/travis/upload.sh
|
# - ports/ci/travis/upload.sh
|
||||||
|
|
||||||
|
|
0
ChangeLog
Normal file
0
ChangeLog
Normal file
|
@ -64,7 +64,7 @@ macx: LIBS += \
|
||||||
-framework IOKit \
|
-framework IOKit \
|
||||||
-framework IOSurface
|
-framework IOSurface
|
||||||
LIBS += \
|
LIBS += \
|
||||||
-L$${OUT_PWD}/VCamUtils/$${BIN_DIR} -lVCamUtils
|
-L$${OUT_PWD}/../VCamUtils/$${BIN_DIR} -lVCamUtils
|
||||||
|
|
||||||
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
||||||
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
||||||
|
|
12
appveyor.yml
12
appveyor.yml
|
@ -62,12 +62,12 @@ build_script:
|
||||||
C:\msys64\usr\bin\bash -lc "cd /c/projects/akvirtualcamera && ./ports/ci/appveyor/build.sh '%INSTALL_PREFIX%'"
|
C:\msys64\usr\bin\bash -lc "cd /c/projects/akvirtualcamera && ./ports/ci/appveyor/build.sh '%INSTALL_PREFIX%'"
|
||||||
)
|
)
|
||||||
|
|
||||||
#after_build:
|
after_build:
|
||||||
# - if "%MSYS2_BUILD%" == "" (
|
- if "%MSYS2_BUILD%" == "" (
|
||||||
# ports\ci\appveyor\deploy.bat
|
ports\ci\appveyor\deploy.bat
|
||||||
# ) else (
|
) else (
|
||||||
# C:\msys64\usr\bin\bash -lc "cd /c/projects/akvirtualcamera && ./ports/ci/appveyor/deploy.sh"
|
C:\msys64\usr\bin\bash -lc "cd /c/projects/akvirtualcamera && ./ports/ci/appveyor/deploy.sh"
|
||||||
# )
|
)
|
||||||
# - ports\ci\appveyor\push_artifacts.bat
|
# - ports\ci\appveyor\push_artifacts.bat
|
||||||
#
|
#
|
||||||
#deploy_script:
|
#deploy_script:
|
||||||
|
|
|
@ -38,7 +38,7 @@ win32 {
|
||||||
DEFAULT_PREFIX = C:/
|
DEFAULT_PREFIX = C:/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
macx: DEFAULT_PREFIX = /Library/CoreMediaIO/Plug-Ins/DAL
|
macx: DEFAULT_PREFIX = /Applications
|
||||||
|
|
||||||
isEmpty(PREFIX): PREFIX = $${DEFAULT_PREFIX}
|
isEmpty(PREFIX): PREFIX = $${DEFAULT_PREFIX}
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,12 @@ REM
|
||||||
REM Web-Site: http://webcamoid.github.io/
|
REM Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
if "%PLATFORM%" == "x86" (
|
if "%PLATFORM%" == "x86" (
|
||||||
set FF_ARCH=win32
|
|
||||||
set GST_ARCH=x86
|
|
||||||
set VC_ARGS=x86
|
|
||||||
set PYTHON_PATH=C:\%PYTHON_VERSION%
|
set PYTHON_PATH=C:\%PYTHON_VERSION%
|
||||||
) else (
|
) else (
|
||||||
set FF_ARCH=win64
|
|
||||||
set GST_ARCH=x86_64
|
|
||||||
set VC_ARGS=amd64
|
|
||||||
set PYTHON_PATH=C:\%PYTHON_VERSION%-x64
|
set PYTHON_PATH=C:\%PYTHON_VERSION%-x64
|
||||||
)
|
)
|
||||||
|
|
||||||
set MAKE_PATH=%TOOLSDIR%\bin\%MAKETOOL%.exe
|
set MAKE_PATH=%TOOLSDIR%\bin\%MAKETOOL%.exe
|
||||||
set GSTREAMER_DEV_PATH=C:\gstreamer\1.0\%GST_ARCH%
|
set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%PATH%
|
||||||
set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%CD%\ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-shared\bin;%GSTREAMER_DEV_PATH%\bin;%PATH%
|
|
||||||
|
|
||||||
%PYTHON_PATH%\python.exe ports\deploy\deploy.py
|
%PYTHON_PATH%\python.exe ports\deploy\deploy.py
|
||||||
|
|
|
@ -18,73 +18,13 @@
|
||||||
#
|
#
|
||||||
# Web-Site: http://webcamoid.github.io/
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
if [ "${ARCH_ROOT_BUILD}" = 1 ]; then
|
if [ "${TRAVIS_OS_NAME}" = linux ]; then
|
||||||
EXEC='sudo ./root.x86_64/bin/arch-chroot root.x86_64'
|
EXEC='sudo ./root.x86_64/bin/arch-chroot root.x86_64'
|
||||||
elif [ "${TRAVIS_OS_NAME}" = linux ] && [ -z "${ANDROID_BUILD}" ]; then
|
|
||||||
if [ -z "${DAILY_BUILD}" ]; then
|
|
||||||
EXEC="docker exec ${DOCKERSYS}"
|
|
||||||
else
|
|
||||||
EXEC="docker exec -e DAILY_BUILD=1 ${DOCKERSYS}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DEPLOYSCRIPT=deployscript.sh
|
DEPLOYSCRIPT=deployscript.sh
|
||||||
|
|
||||||
if [ "${ANDROID_BUILD}" = 1 ]; then
|
if [ "${TRAVIS_OS_NAME}" = linux ]; then
|
||||||
export JAVA_HOME=$(readlink -f /usr/bin/java | sed 's:bin/java::')
|
|
||||||
export ANDROID_HOME="${PWD}/build/android-sdk"
|
|
||||||
export ANDROID_NDK="${PWD}/build/android-ndk"
|
|
||||||
export ANDROID_NDK_HOME=${ANDROID_NDK}
|
|
||||||
export ANDROID_NDK_PLATFORM=android-${ANDROID_PLATFORM}
|
|
||||||
export ANDROID_NDK_ROOT=${ANDROID_NDK}
|
|
||||||
export ANDROID_SDK_ROOT=${ANDROID_HOME}
|
|
||||||
export PATH="${JAVA_HOME}/bin/java:${PATH}"
|
|
||||||
export PATH="$PATH:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin"
|
|
||||||
export PATH="${PATH}:${ANDROID_HOME}/platform-tools"
|
|
||||||
export PATH="${PATH}:${ANDROID_HOME}/emulator"
|
|
||||||
export PATH="${PATH}:${ANDROID_NDK}"
|
|
||||||
export ORIG_PATH="${PATH}"
|
|
||||||
export KEYSTORE_PATH="${PWD}/keystores/debug.keystore"
|
|
||||||
nArchs=$(echo "${TARGET_ARCH}" | tr ':' ' ' | wc -w)
|
|
||||||
lastArch=$(echo "${TARGET_ARCH}" | awk -F: '{print $NF}')
|
|
||||||
|
|
||||||
if [ "${nArchs}" = 1 ]; then
|
|
||||||
export PATH="${PWD}/build/Qt/${QTVER}/android/bin:${PWD}/.local/bin:${ORIG_PATH}"
|
|
||||||
export BUILD_PATH=${PWD}/build-webcamoid-${lastArch}
|
|
||||||
|
|
||||||
python3 ports/deploy/deploy.py
|
|
||||||
else
|
|
||||||
pkgMerge=
|
|
||||||
|
|
||||||
for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do
|
|
||||||
if [ ! -z "${pkgMerge}" ]; then
|
|
||||||
pkgMerge=${pkgMerge}:
|
|
||||||
fi
|
|
||||||
|
|
||||||
pkgMerge=${pkgMerge}${PWD}/build-webcamoid-${arch_}
|
|
||||||
done
|
|
||||||
|
|
||||||
for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do
|
|
||||||
export PATH="${PWD}/build/Qt/${QTVER}/android/bin:${PWD}/.local/bin:${ORIG_PATH}"
|
|
||||||
export BUILD_PATH=${PWD}/build-webcamoid-${arch_}
|
|
||||||
|
|
||||||
if [ "${arch_}" = "${lastArch}" ]; then
|
|
||||||
export PACKAGES_PREPARE_ONLY=0
|
|
||||||
export PACKAGES_MERGE="${pkgMerge}"
|
|
||||||
else
|
|
||||||
export PACKAGES_PREPARE_ONLY=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export NO_SHOW_PKG_DATA_INFO=1
|
|
||||||
|
|
||||||
python3 ports/deploy/deploy.py
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "${PWD}/ports/deploy/packages_auto"
|
|
||||||
cp -rvf "${PWD}/build-webcamoid-${lastArch}/ports/deploy/packages_auto"/* \
|
|
||||||
"${PWD}/ports/deploy/packages_auto"
|
|
||||||
elif [ "${ARCH_ROOT_BUILD}" = 1 ]; then
|
|
||||||
sudo mount --bind root.x86_64 root.x86_64
|
sudo mount --bind root.x86_64 root.x86_64
|
||||||
sudo mount --bind $HOME root.x86_64/$HOME
|
sudo mount --bind $HOME root.x86_64/$HOME
|
||||||
|
|
||||||
|
@ -113,17 +53,6 @@ EOF
|
||||||
${EXEC} bash $HOME/${DEPLOYSCRIPT}
|
${EXEC} bash $HOME/${DEPLOYSCRIPT}
|
||||||
sudo umount root.x86_64/$HOME
|
sudo umount root.x86_64/$HOME
|
||||||
sudo umount root.x86_64
|
sudo umount root.x86_64
|
||||||
elif [ "${TRAVIS_OS_NAME}" = linux ]; then
|
|
||||||
cat << EOF > ${DEPLOYSCRIPT}
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
export PATH="\$PWD/.local/bin:\$PATH"
|
|
||||||
xvfb-run --auto-servernum python3 ports/deploy/deploy.py
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x ${DEPLOYSCRIPT}
|
|
||||||
|
|
||||||
${EXEC} bash ${DEPLOYSCRIPT}
|
|
||||||
elif [ "${TRAVIS_OS_NAME}" = osx ]; then
|
elif [ "${TRAVIS_OS_NAME}" = osx ]; then
|
||||||
${EXEC} python3 ports/deploy/deploy.py
|
${EXEC} python3 ports/deploy/deploy.py
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -38,34 +38,23 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
|
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.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', self.targetSystem)
|
||||||
self.detectQt(os.path.join(self.buildDir, 'StandAlone'))
|
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
||||||
self.rootInstallDir = os.path.join(self.installDir, 'Applications')
|
self.rootInstallDir = os.path.join(self.installDir, 'Applications')
|
||||||
self.programName = 'webcamoid'
|
self.programName = 'AkVirtualCamera'
|
||||||
self.appBundleDir = os.path.join(self.rootInstallDir, self.programName + '.app')
|
self.appBundleDir = os.path.join(self.rootInstallDir, self.programName + '.plugin')
|
||||||
self.execPrefixDir = os.path.join(self.appBundleDir, 'Contents')
|
self.execPrefixDir = os.path.join(self.appBundleDir, 'Contents')
|
||||||
self.binaryInstallDir = os.path.join(self.execPrefixDir, 'MacOS')
|
self.binaryInstallDir = os.path.join(self.execPrefixDir, 'MacOS')
|
||||||
self.libInstallDir = os.path.join(self.execPrefixDir, 'Frameworks')
|
|
||||||
self.qmlInstallDir = os.path.join(self.execPrefixDir, 'Resources/qml')
|
|
||||||
self.pluginsInstallDir = os.path.join(self.execPrefixDir, 'Plugins')
|
|
||||||
self.qtConf = os.path.join(self.execPrefixDir, 'Resources/qt.conf')
|
|
||||||
self.qmlRootDirs = ['StandAlone/share/qml', 'libAvKys/Plugins']
|
|
||||||
self.mainBinary = os.path.join(self.binaryInstallDir, self.programName)
|
self.mainBinary = os.path.join(self.binaryInstallDir, self.programName)
|
||||||
self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri'))
|
self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri'))
|
||||||
self.detectMake()
|
self.detectMake()
|
||||||
xspec = self.qmakeQuery(var='QMAKE_XSPEC')
|
|
||||||
|
|
||||||
if 'android' in xspec:
|
|
||||||
self.targetSystem = 'android'
|
|
||||||
|
|
||||||
self.binarySolver = tools.binary_mach.DeployToolsBinary()
|
self.binarySolver = tools.binary_mach.DeployToolsBinary()
|
||||||
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
||||||
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
|
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
|
||||||
self.dependencies = []
|
self.dependencies = []
|
||||||
self.installerConfig = os.path.join(self.installDir, 'installer/config')
|
self.installerConfig = os.path.join(self.installDir, 'installer/config')
|
||||||
self.installerPackages = os.path.join(self.installDir, 'installer/packages')
|
self.installerPackages = os.path.join(self.installDir, 'installer/packages')
|
||||||
self.appIcon = os.path.join(self.execPrefixDir, 'Resources/{0}.icns'.format(self.programName))
|
self.appIcon = os.path.join(self.rootDir, 'share/TestFrame/webcamoid.png')
|
||||||
self.licenseFile = os.path.join(self.rootDir, 'COPYING')
|
self.licenseFile = os.path.join(self.rootDir, 'COPYING')
|
||||||
self.installerRunProgram = '@TargetDir@/{0}.app/Contents/MacOS/{0}'.format(self.programName)
|
|
||||||
self.installerTargetDir = '@ApplicationsDir@/' + self.programName
|
self.installerTargetDir = '@ApplicationsDir@/' + self.programName
|
||||||
self.installerScript = os.path.join(self.rootDir, 'ports/deploy/installscript.mac.qs')
|
self.installerScript = os.path.join(self.rootDir, 'ports/deploy/installscript.mac.qs')
|
||||||
self.changeLog = os.path.join(self.rootDir, 'ChangeLog')
|
self.changeLog = os.path.join(self.rootDir, 'ChangeLog')
|
||||||
|
@ -77,160 +66,14 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
print('Executing make install')
|
print('Executing make install')
|
||||||
self.makeInstall(self.buildDir, self.installDir)
|
self.makeInstall(self.buildDir, self.installDir)
|
||||||
self.detectTargetArch()
|
self.detectTargetArch()
|
||||||
|
|
||||||
print('Copying Qml modules\n')
|
|
||||||
self.solvedepsQml()
|
|
||||||
print('\nCopying required plugins\n')
|
|
||||||
self.solvedepsPlugins()
|
|
||||||
print('\nCopying required libs\n')
|
|
||||||
self.solvedepsLibs()
|
|
||||||
print('\nWritting qt.conf file')
|
|
||||||
self.writeQtConf()
|
|
||||||
print('Stripping symbols')
|
print('Stripping symbols')
|
||||||
self.binarySolver.stripSymbols(self.installDir)
|
self.binarySolver.stripSymbols(self.installDir)
|
||||||
print('Resetting file permissions')
|
print('Resetting file permissions')
|
||||||
self.binarySolver.resetFilePermissions(self.rootInstallDir,
|
self.binarySolver.resetFilePermissions(self.rootInstallDir,
|
||||||
self.binaryInstallDir)
|
self.binaryInstallDir)
|
||||||
print('Removing unnecessary files')
|
|
||||||
self.removeUnneededFiles(self.libInstallDir)
|
|
||||||
print('Fixing rpaths\n')
|
|
||||||
self.fixRpaths()
|
|
||||||
print('\nWritting build system information\n')
|
print('\nWritting build system information\n')
|
||||||
self.writeBuildInfo()
|
self.writeBuildInfo()
|
||||||
|
|
||||||
def solvedepsLibs(self):
|
|
||||||
deps = sorted(self.binarySolver.scanDependencies(self.installDir))
|
|
||||||
|
|
||||||
for dep in deps:
|
|
||||||
depPath = os.path.join(self.libInstallDir, os.path.basename(dep))
|
|
||||||
|
|
||||||
if dep != depPath:
|
|
||||||
print(' {} -> {}'.format(dep, depPath))
|
|
||||||
self.copy(dep, depPath, not dep.endswith('.framework'))
|
|
||||||
self.dependencies.append(dep)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def removeUnneededFiles(path):
|
|
||||||
adirs = set()
|
|
||||||
afiles = set()
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(path):
|
|
||||||
for d in dirs:
|
|
||||||
if d == 'Headers':
|
|
||||||
adirs.add(os.path.join(root, d))
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
if f == 'Headers' or f.endswith('.prl'):
|
|
||||||
afiles.add(os.path.join(root, f))
|
|
||||||
|
|
||||||
for adir in adirs:
|
|
||||||
try:
|
|
||||||
shutil.rmtree(adir, True)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for afile in afiles:
|
|
||||||
try:
|
|
||||||
if os.path.islink(afile):
|
|
||||||
os.unlink(afile)
|
|
||||||
else:
|
|
||||||
os.remove(afile)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def fixLibRpath(self, mutex, mach):
|
|
||||||
rpath = os.path.join('@executable_path',
|
|
||||||
os.path.relpath(self.libInstallDir,
|
|
||||||
self.binaryInstallDir))
|
|
||||||
log = '\tFixed {}\n\n'.format(mach)
|
|
||||||
machInfo = self.binarySolver.dump(mach)
|
|
||||||
|
|
||||||
# Change rpath
|
|
||||||
if mach.startswith(self.binaryInstallDir):
|
|
||||||
log += '\t\tChanging rpath to {}\n'.format(rpath)
|
|
||||||
|
|
||||||
for oldRpath in machInfo['rpaths']:
|
|
||||||
process = subprocess.Popen(['install_name_tool', # nosec
|
|
||||||
'-delete_rpath', oldRpath, mach],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
process = subprocess.Popen(['install_name_tool', # nosec
|
|
||||||
'-add_rpath', rpath, mach],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
# Change ID
|
|
||||||
if mach.startswith(self.binaryInstallDir):
|
|
||||||
newMachId = machInfo['id']
|
|
||||||
elif mach.startswith(self.libInstallDir):
|
|
||||||
newMachId = mach.replace(self.libInstallDir, rpath)
|
|
||||||
else:
|
|
||||||
newMachId = os.path.basename(mach)
|
|
||||||
|
|
||||||
if newMachId != machInfo['id']:
|
|
||||||
log += '\t\tChanging ID to {}\n'.format(newMachId)
|
|
||||||
|
|
||||||
process = subprocess.Popen(['install_name_tool', # nosec
|
|
||||||
'-id', newMachId, mach],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
# Change library links
|
|
||||||
for dep in machInfo['imports']:
|
|
||||||
if dep.startswith(rpath):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if self.binarySolver.isExcluded(dep):
|
|
||||||
continue
|
|
||||||
|
|
||||||
basename = os.path.basename(dep)
|
|
||||||
framework = ''
|
|
||||||
inFrameworkPath = ''
|
|
||||||
|
|
||||||
if not basename.endswith('.dylib'):
|
|
||||||
frameworkPath = dep[: dep.rfind('.framework')] + '.framework'
|
|
||||||
framework = os.path.basename(frameworkPath)
|
|
||||||
inFrameworkPath = os.path.join(framework, dep.replace(frameworkPath + '/', ''))
|
|
||||||
|
|
||||||
newDepPath = os.path.join(rpath, basename if len(framework) < 1 else inFrameworkPath)
|
|
||||||
|
|
||||||
if dep != newDepPath:
|
|
||||||
log += '\t\t{} -> {}\n'.format(dep, newDepPath)
|
|
||||||
|
|
||||||
process = subprocess.Popen(['install_name_tool', # nosec
|
|
||||||
'-change', dep, newDepPath, mach],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
mutex.acquire()
|
|
||||||
print(log)
|
|
||||||
mutex.release()
|
|
||||||
|
|
||||||
def fixRpaths(self):
|
|
||||||
path = os.path.join(self.execPrefixDir)
|
|
||||||
mutex = threading.Lock()
|
|
||||||
threads = []
|
|
||||||
|
|
||||||
for mach in self.binarySolver.find(path):
|
|
||||||
thread = threading.Thread(target=self.fixLibRpath, args=(mutex, mach,))
|
|
||||||
threads.append(thread)
|
|
||||||
|
|
||||||
while threading.active_count() >= self.njobs:
|
|
||||||
time.sleep(0.25)
|
|
||||||
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
for thread in threads:
|
|
||||||
thread.join()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def searchPackageFor(cellarPath, path):
|
|
||||||
if not path.startswith(cellarPath):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
return ' '.join(path.replace(cellarPath + os.sep, '').split(os.sep)[0: 2])
|
|
||||||
|
|
||||||
def commitHash(self):
|
def commitHash(self):
|
||||||
try:
|
try:
|
||||||
process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec
|
process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec
|
||||||
|
@ -256,8 +99,18 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
return stdout.decode(sys.getdefaultencoding()).strip()
|
return stdout.decode(sys.getdefaultencoding()).strip()
|
||||||
|
|
||||||
def writeBuildInfo(self):
|
def writeBuildInfo(self):
|
||||||
|
try:
|
||||||
|
os.makedirs(self.pkgsDir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
resourcesDir = os.path.join(self.execPrefixDir, 'Resources')
|
resourcesDir = os.path.join(self.execPrefixDir, 'Resources')
|
||||||
os.makedirs(self.pkgsDir)
|
|
||||||
|
try:
|
||||||
|
os.makedirs(resourcesDir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
depsInfoFile = os.path.join(resourcesDir, 'build-info.txt')
|
depsInfoFile = os.path.join(resourcesDir, 'build-info.txt')
|
||||||
|
|
||||||
# Write repository info.
|
# Write repository info.
|
||||||
|
@ -300,35 +153,6 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
print()
|
print()
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
|
|
||||||
os.environ['LC_ALL'] = 'C'
|
|
||||||
brew = self.whereBin('brew')
|
|
||||||
|
|
||||||
if len(brew) < 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
process = subprocess.Popen([brew, '--cellar'], # nosec
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
stdout, _ = process.communicate()
|
|
||||||
cellarPath = stdout.decode(sys.getdefaultencoding()).strip()
|
|
||||||
|
|
||||||
# Write binary dependencies info.
|
|
||||||
|
|
||||||
packages = set()
|
|
||||||
|
|
||||||
for dep in self.dependencies:
|
|
||||||
packageInfo = self.searchPackageFor(cellarPath, dep)
|
|
||||||
|
|
||||||
if len(packageInfo) > 0:
|
|
||||||
packages.add(packageInfo)
|
|
||||||
|
|
||||||
packages = sorted(packages)
|
|
||||||
|
|
||||||
with open(depsInfoFile, 'a') as f:
|
|
||||||
for packge in packages:
|
|
||||||
print(' ' + packge)
|
|
||||||
f.write(packge + '\n')
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def hrSize(size):
|
def hrSize(size):
|
||||||
i = int(math.log(size) // math.log(1024))
|
i = int(math.log(size) // math.log(1024))
|
||||||
|
@ -365,109 +189,6 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
|
|
||||||
return size
|
return size
|
||||||
|
|
||||||
# https://asmaloney.com/2013/07/howto/packaging-a-mac-os-x-application-using-a-dmg/
|
|
||||||
def createPortable(self, mutex):
|
|
||||||
staggingDir = os.path.join(self.installDir, 'stagging')
|
|
||||||
|
|
||||||
if not os.path.exists(staggingDir):
|
|
||||||
os.makedirs(staggingDir)
|
|
||||||
|
|
||||||
self.copy(self.appBundleDir,
|
|
||||||
os.path.join(staggingDir, self.programName + '.app'))
|
|
||||||
imageSize = self.dirSize(staggingDir)
|
|
||||||
tmpDmg = os.path.join(self.installDir, self.programName + '_tmp.dmg')
|
|
||||||
volumeName = "{}-portable-{}".format(self.programName,
|
|
||||||
self.programVersion)
|
|
||||||
|
|
||||||
process = subprocess.Popen(['hdiutil', 'create', # nosec
|
|
||||||
'-srcfolder', staggingDir,
|
|
||||||
'-volname', volumeName,
|
|
||||||
'-fs', 'HFS+',
|
|
||||||
'-fsargs', '-c c=64,a=16,e=16',
|
|
||||||
'-format', 'UDRW',
|
|
||||||
'-size', str(math.ceil(imageSize * 1.1)),
|
|
||||||
tmpDmg],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
process = subprocess.Popen(['hdiutil', # nosec
|
|
||||||
'attach',
|
|
||||||
'-readwrite',
|
|
||||||
'-noverify',
|
|
||||||
tmpDmg],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
stdout, _ = process.communicate()
|
|
||||||
device = ''
|
|
||||||
|
|
||||||
for line in stdout.split(b'\n'):
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if len(line) < 1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
dev = line.split()
|
|
||||||
|
|
||||||
if len(dev) > 2:
|
|
||||||
device = dev[0].decode(sys.getdefaultencoding())
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
time.sleep(2)
|
|
||||||
volumePath = os.path.join('/Volumes', volumeName)
|
|
||||||
volumeIcon = os.path.join(volumePath, '.VolumeIcon.icns')
|
|
||||||
self.copy(self.appIcon, volumeIcon)
|
|
||||||
|
|
||||||
process = subprocess.Popen(['SetFile', # nosec
|
|
||||||
'-c', 'icnC',
|
|
||||||
volumeIcon],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
process = subprocess.Popen(['SetFile', # nosec
|
|
||||||
'-a', 'C',
|
|
||||||
volumePath],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
appsShortcut = os.path.join(volumePath, 'Applications')
|
|
||||||
|
|
||||||
if not os.path.exists(appsShortcut):
|
|
||||||
os.symlink('/Applications', appsShortcut)
|
|
||||||
|
|
||||||
os.sync()
|
|
||||||
|
|
||||||
process = subprocess.Popen(['hdiutil', # nosec
|
|
||||||
'detach',
|
|
||||||
device],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
packagePath = \
|
|
||||||
os.path.join(self.pkgsDir,
|
|
||||||
'{}-portable-{}-{}.dmg'.format(self.programName,
|
|
||||||
self.programVersion,
|
|
||||||
platform.machine()))
|
|
||||||
|
|
||||||
if not os.path.exists(self.pkgsDir):
|
|
||||||
os.makedirs(self.pkgsDir)
|
|
||||||
|
|
||||||
if os.path.exists(packagePath):
|
|
||||||
os.remove(packagePath)
|
|
||||||
|
|
||||||
process = subprocess.Popen(['hdiutil', # nosec
|
|
||||||
'convert',
|
|
||||||
tmpDmg,
|
|
||||||
'-format', 'UDZO',
|
|
||||||
'-imagekey', 'zlib-level=9',
|
|
||||||
'-o', packagePath],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
mutex.acquire()
|
|
||||||
print('Created portable package:')
|
|
||||||
self.printPackageInfo(packagePath)
|
|
||||||
mutex.release()
|
|
||||||
|
|
||||||
def createAppInstaller(self, mutex):
|
def createAppInstaller(self, mutex):
|
||||||
packagePath = self.createInstaller()
|
packagePath = self.createInstaller()
|
||||||
|
|
||||||
|
@ -481,9 +202,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
mutex = threading.Lock()
|
mutex = threading.Lock()
|
||||||
|
threads = []
|
||||||
threads = [threading.Thread(target=self.createPortable, args=(mutex,))]
|
packagingTools = []
|
||||||
packagingTools = ['dmg']
|
|
||||||
|
|
||||||
if self.qtIFW != '':
|
if self.qtIFW != '':
|
||||||
threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,)))
|
threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,)))
|
||||||
|
|
|
@ -10,4 +10,77 @@ Component.prototype.beginInstallation = function()
|
||||||
Component.prototype.createOperations = function()
|
Component.prototype.createOperations = function()
|
||||||
{
|
{
|
||||||
component.createOperations();
|
component.createOperations();
|
||||||
|
|
||||||
|
// Remove old plugin
|
||||||
|
if (installer.isInstaller()) {
|
||||||
|
component.addOperation("ConsumeOutput",
|
||||||
|
"AkPluginSymlink",
|
||||||
|
"/usr/bin/readlink",
|
||||||
|
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin");
|
||||||
|
|
||||||
|
if (installer.value("AkPluginSymlink") == "")
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"rm",
|
||||||
|
"-rf",
|
||||||
|
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a symlink to the plugin.
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"ln",
|
||||||
|
"-s",
|
||||||
|
"@TargetDir@/@Name@.plugin",
|
||||||
|
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin",
|
||||||
|
"UNDOEXECUTE",
|
||||||
|
"rm",
|
||||||
|
"-f",
|
||||||
|
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin");
|
||||||
|
|
||||||
|
// Set assistant daemon.
|
||||||
|
let daemonPlist = "/Library/LaunchAgents/org.webcamoid.cmio.AkVCam.Assistant.plist"
|
||||||
|
let plistContents = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
|
||||||
|
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||||
|
+ "<plist version=\"1.0\">\n"
|
||||||
|
+ " <dict>\n"
|
||||||
|
+ " <key>Label</key>\n"
|
||||||
|
+ " <string>org.webcamoid.cmio.AkVCam.Assistant</string>\n"
|
||||||
|
+ " <key>ProgramArguments</key>\n"
|
||||||
|
+ " <array>\n"
|
||||||
|
+ " <string>"
|
||||||
|
+ installer.value("TargetDir")
|
||||||
|
+ "/AkVirtualCamera.plugin/Contents/Resources/AkVCamAssistant"
|
||||||
|
+ "</string>\n"
|
||||||
|
+ " <string>--timeout</string>\n"
|
||||||
|
+ " <string>300.0</string>\n"
|
||||||
|
+ " </array>\n"
|
||||||
|
+ " <key>MachServices</key>\n"
|
||||||
|
+ " <dict>\n"
|
||||||
|
+ " <key>org.webcamoid.cmio.AkVCam.Assistant</key>\n"
|
||||||
|
+ " <true/>\n"
|
||||||
|
+ " </dict>\n"
|
||||||
|
+ " </dict>\n"
|
||||||
|
+ "</plist>\n";
|
||||||
|
component.addElevatedOperation("Delete", daemonPlist);
|
||||||
|
component.addElevatedOperation("AppendFile", daemonPlist, plistContents);
|
||||||
|
|
||||||
|
// Load assistant daemon.
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"launchctl", "load", "-w", daemonPlist,
|
||||||
|
"UNDOEXECUTE",
|
||||||
|
"launchctl", "unload", "-w", daemonPlist);
|
||||||
|
|
||||||
|
if (installer.isUninstaller())
|
||||||
|
component.addElevatedOperation("Delete", daemonPlist);
|
||||||
|
|
||||||
|
if (installer.value("TargetDir") != "/Applications/" + installer.value("Name"))
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"ln",
|
||||||
|
"-s",
|
||||||
|
"@TargetDir@",
|
||||||
|
"/Applications/@Name@",
|
||||||
|
"UNDOEXECUTE",
|
||||||
|
"rm",
|
||||||
|
"-f",
|
||||||
|
"/Applications/@Name@");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,44 +10,4 @@ Component.prototype.beginInstallation = function()
|
||||||
Component.prototype.createOperations = function()
|
Component.prototype.createOperations = function()
|
||||||
{
|
{
|
||||||
component.createOperations();
|
component.createOperations();
|
||||||
|
|
||||||
component.addOperation("InstallIcons", "@TargetDir@/share/icons" );
|
|
||||||
component.addOperation("CreateDesktopEntry",
|
|
||||||
"Webcamoid.desktop",
|
|
||||||
"Name=Webcamoid\n"
|
|
||||||
+ "GenericName=Webcam Capture Software\n"
|
|
||||||
+ "GenericName[ca]=Programari de Captura de Càmera web\n"
|
|
||||||
+ "GenericName[de]=Webcam-Capture-Software\n"
|
|
||||||
+ "GenericName[el]=κάμερα συλλαμβάνει το λογισμικό\n"
|
|
||||||
+ "GenericName[es]=Programa para Captura de la Webcam\n"
|
|
||||||
+ "GenericName[fr]=Logiciel de Capture Webcam\n"
|
|
||||||
+ "GenericName[gl]=Programa de Captura de Webcam\n"
|
|
||||||
+ "GenericName[it]=Webcam Capture Software\n"
|
|
||||||
+ "GenericName[ja]=ウェブカメラのキャプチャソフトウェア\n"
|
|
||||||
+ "GenericName[ko]=웹캠 캡처 소프트웨어\n"
|
|
||||||
+ "GenericName[pt]=Software de Captura de Webcam\n"
|
|
||||||
+ "GenericName[ru]=Веб-камера захвата программного обеспечения\n"
|
|
||||||
+ "GenericName[zh_CN]=摄像头捕捉软件\n"
|
|
||||||
+ "GenericName[zh_TW]=攝像頭捕捉軟件\n"
|
|
||||||
+ "Comment=Take photos and record videos with your webcam\n"
|
|
||||||
+ "Comment[ca]=Fer fotos i gravar vídeos amb la seva webcam\n"
|
|
||||||
+ "Comment[de]=Maak foto's en video's opnemen met uw webcam\n"
|
|
||||||
+ "Comment[el]=Τραβήξτε φωτογραφίες και εγγραφή βίντεο με την κάμερα σας\n"
|
|
||||||
+ "Comment[es]=Tome fotos y grabe videos con su camara web\n"
|
|
||||||
+ "Comment[fr]=Prenez des photos et enregistrer des vidéos avec votre webcam\n"
|
|
||||||
+ "Comment[gl]=Facer fotos e gravar vídeos coa súa cámara web\n"
|
|
||||||
+ "Comment[it]=Scatta foto e registrare video con la tua webcam\n"
|
|
||||||
+ "Comment[ja]=ウェブカメラで写真や記録ビデオを撮影\n"
|
|
||||||
+ "Comment[ko]=웹캠으로 사진과 기록 비디오를 촬영\n"
|
|
||||||
+ "Comment[pt]=Tirar fotos e gravar vídeos com sua webcam\n"
|
|
||||||
+ "Comment[ru]=Возьмите фотографии и записывать видео с веб-камеры\n"
|
|
||||||
+ "Comment[zh_CN]=拍摄照片和录制视频与您的摄像头\n"
|
|
||||||
+ "Comment[zh_TW]=拍攝照片和錄製視頻與您的攝像頭\n"
|
|
||||||
+ "Keywords=photo;video;webcam;\n"
|
|
||||||
+ "Exec=" + installer.value("RunProgram") + "\n"
|
|
||||||
+ "Icon=webcamoid\n"
|
|
||||||
+ "Terminal=false\n"
|
|
||||||
+ "Type=Application\n"
|
|
||||||
+ "Categories=AudioVideo;Player;Qt;\n"
|
|
||||||
+ "StartupNotify=true\n");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
[Package]
|
[Package]
|
||||||
appName = Webcamoid
|
appName = AkVirtualCamera
|
||||||
description = Webcamoid, The ultimate webcam suite!
|
description = AkVirtualCamera, virtual camera for Mac and Windows
|
||||||
url = https://webcamoid.github.io/
|
url = https://github.com/webcamoid/akvirtualcamera
|
||||||
titleColor = #3F1F7F
|
titleColor = #3F1F7F
|
||||||
runMessage = Launch Webcamoid now!
|
|
||||||
licenseDescription = GNU General Public License v3.0
|
licenseDescription = GNU General Public License v3.0
|
||||||
|
|
|
@ -47,6 +47,7 @@ class DeployToolsQt(tools.utils.DeployToolsUtils):
|
||||||
self.dependencies = []
|
self.dependencies = []
|
||||||
self.binarySolver = None
|
self.binarySolver = None
|
||||||
self.installerConfig = ''
|
self.installerConfig = ''
|
||||||
|
self.installerRunProgram = ''
|
||||||
|
|
||||||
def detectQt(self, path=''):
|
def detectQt(self, path=''):
|
||||||
self.detectQmake(path)
|
self.detectQmake(path)
|
||||||
|
@ -495,7 +496,7 @@ class DeployToolsQt(tools.utils.DeployToolsUtils):
|
||||||
packageConf.read(self.packageConfig, 'utf-8')
|
packageConf.read(self.packageConfig, 'utf-8')
|
||||||
|
|
||||||
# Create layout
|
# Create layout
|
||||||
componentName = 'com.{0}prj.{0}'.format(self.programName)
|
componentName = 'com.webcamoidprj.{0}'.format(self.programName)
|
||||||
packageDir = os.path.join(self.installerPackages, componentName)
|
packageDir = os.path.join(self.installerPackages, componentName)
|
||||||
|
|
||||||
if not os.path.exists(self.installerConfig):
|
if not os.path.exists(self.installerConfig):
|
||||||
|
@ -541,11 +542,13 @@ class DeployToolsQt(tools.utils.DeployToolsUtils):
|
||||||
config.write(' <InstallerWindowIcon>{}</InstallerWindowIcon>\n'.format(iconName))
|
config.write(' <InstallerWindowIcon>{}</InstallerWindowIcon>\n'.format(iconName))
|
||||||
config.write(' <InstallerApplicationIcon>{}</InstallerApplicationIcon>\n'.format(iconName))
|
config.write(' <InstallerApplicationIcon>{}</InstallerApplicationIcon>\n'.format(iconName))
|
||||||
config.write(' <Logo>{}</Logo>\n'.format(iconName))
|
config.write(' <Logo>{}</Logo>\n'.format(iconName))
|
||||||
config.write(' <TitleColor>{}</TitleColor>\n'.format(packageConf['Package']['titleColor'].strip()))
|
|
||||||
config.write(' <RunProgram>{}</RunProgram>\n'.format(self.installerRunProgram))
|
if self.installerRunProgram != '':
|
||||||
config.write(' <RunProgramDescription>{}</RunProgramDescription>\n'.format(packageConf['Package']['runMessage'].strip()))
|
config.write(' <RunProgram>{}</RunProgram>\n'.format(self.installerRunProgram))
|
||||||
config.write(' <StartMenuDir>{}</StartMenuDir>\n'.format(appName))
|
config.write(' <RunProgramDescription>{}</RunProgramDescription>\n'.format(packageConf['Package']['runMessage'].strip()))
|
||||||
config.write(' <MaintenanceToolName>{}MaintenanceTool</MaintenanceToolName>\n'.format(appName))
|
config.write(' <StartMenuDir>{}</StartMenuDir>\n'.format(appName))
|
||||||
|
|
||||||
|
config.write(' <MaintenanceToolName>Uninstall</MaintenanceToolName>\n')
|
||||||
config.write(' <AllowNonAsciiCharacters>true</AllowNonAsciiCharacters>\n')
|
config.write(' <AllowNonAsciiCharacters>true</AllowNonAsciiCharacters>\n')
|
||||||
config.write(' <TargetDir>{}</TargetDir>\n'.format(self.installerTargetDir))
|
config.write(' <TargetDir>{}</TargetDir>\n'.format(self.installerTargetDir))
|
||||||
config.write('</Installer>\n')
|
config.write('</Installer>\n')
|
||||||
|
@ -582,6 +585,7 @@ class DeployToolsQt(tools.utils.DeployToolsUtils):
|
||||||
f.write(' <Default>true</Default>\n')
|
f.write(' <Default>true</Default>\n')
|
||||||
f.write(' <ForcedInstallation>true</ForcedInstallation>\n')
|
f.write(' <ForcedInstallation>true</ForcedInstallation>\n')
|
||||||
f.write(' <Essential>false</Essential>\n')
|
f.write(' <Essential>false</Essential>\n')
|
||||||
|
f.write(' <RequiresAdminRights>true</RequiresAdminRights>\n')
|
||||||
f.write('</Package>\n')
|
f.write('</Package>\n')
|
||||||
|
|
||||||
# Remove old file
|
# Remove old file
|
||||||
|
|
Loading…
Reference in a new issue