Using WebcamoidDeployTools.
This commit is contained in:
parent
e5097d3911
commit
14265e1220
19 changed files with 44 additions and 2382 deletions
|
@ -18,5 +18,10 @@
|
||||||
#
|
#
|
||||||
# Web-Site: http://webcamoid.github.io/
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
cd ports/deploy
|
||||||
|
git clone https://github.com/webcamoid/DeployTools.git
|
||||||
|
cd ../..
|
||||||
|
|
||||||
export PATH=/mingw64/bin:$PATH
|
export PATH=/mingw64/bin:$PATH
|
||||||
|
export PYTHONPATH="${PWD}/ports/deploy/DeployTools"
|
||||||
python3 ports/deploy/deploy.py
|
python3 ports/deploy/deploy.py
|
||||||
|
|
|
@ -22,6 +22,10 @@ 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'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
cd ports/deploy
|
||||||
|
git clone https://github.com/webcamoid/DeployTools.git
|
||||||
|
cd ../..
|
||||||
|
|
||||||
DEPLOYSCRIPT=deployscript.sh
|
DEPLOYSCRIPT=deployscript.sh
|
||||||
|
|
||||||
if [ "${TRAVIS_OS_NAME}" = linux ]; then
|
if [ "${TRAVIS_OS_NAME}" = linux ]; then
|
||||||
|
@ -34,6 +38,7 @@ if [ "${TRAVIS_OS_NAME}" = linux ]; then
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
export HOME=$HOME
|
export HOME=$HOME
|
||||||
export PATH="$TRAVIS_BUILD_DIR/.local/bin:\$PATH"
|
export PATH="$TRAVIS_BUILD_DIR/.local/bin:\$PATH"
|
||||||
|
export PYTHONPATH="\$PWD/ports/deploy/DeployTools"
|
||||||
export WINEPREFIX=/opt/.wine
|
export WINEPREFIX=/opt/.wine
|
||||||
cd $TRAVIS_BUILD_DIR
|
cd $TRAVIS_BUILD_DIR
|
||||||
EOF
|
EOF
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
#
|
#
|
||||||
# Web-Site: http://webcamoid.github.io/
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
import tools.utils
|
from WebcamoidDeployTools import DTUtils
|
||||||
|
|
||||||
|
|
||||||
if __name__ =='__main__':
|
if __name__ =='__main__':
|
||||||
system = tools.utils.DeployToolsUtils().system
|
system = DTUtils.Utils().system
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
import tools.utils
|
|
||||||
|
|
||||||
class DeployBase(tools.utils.DeployToolsUtils):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
|
|
||||||
self.buildDir = os.environ['BUILD_PATH'] if 'BUILD_PATH' in os.environ else self.rootDir
|
|
||||||
self.installDir = os.path.join(self.rootDir, 'ports/deploy/temp_priv/root')
|
|
||||||
self.rootInstallDir = ''
|
|
||||||
self.pkgsDir = os.path.join(self.rootDir,
|
|
||||||
'ports/deploy/packages_auto',
|
|
||||||
sys.platform if os.name == 'posix' else os.name)
|
|
||||||
self.programVersion = ''
|
|
||||||
self.qmake = ''
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
deployInfo = 'Python version: {}\n' \
|
|
||||||
'Root directory: {}\n' \
|
|
||||||
'Build directory: {}\n' \
|
|
||||||
'Install directory: {}\n' \
|
|
||||||
'Packages directory: {}\n' \
|
|
||||||
'System: {}\n' \
|
|
||||||
'Architecture: {}\n' \
|
|
||||||
'Target system: {}\n' \
|
|
||||||
'Target architecture: {}\n' \
|
|
||||||
'Number of threads: {}\n' \
|
|
||||||
'Program version: {}\n' \
|
|
||||||
'Make executable: {}\n' \
|
|
||||||
'Qmake executable: {}'. \
|
|
||||||
format(platform.python_version(),
|
|
||||||
self.rootDir,
|
|
||||||
self.buildDir,
|
|
||||||
self.installDir,
|
|
||||||
self.pkgsDir,
|
|
||||||
self.system,
|
|
||||||
self.arch,
|
|
||||||
self.targetSystem,
|
|
||||||
self.targetArch,
|
|
||||||
self.njobs,
|
|
||||||
self.programVersion,
|
|
||||||
self.make,
|
|
||||||
self.qmake)
|
|
||||||
|
|
||||||
return deployInfo
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
print('Deploy info\n')
|
|
||||||
print(self)
|
|
||||||
print('\nPreparing for software packaging\n')
|
|
||||||
self.prepare()
|
|
||||||
|
|
||||||
if not 'NO_SHOW_PKG_DATA_INFO' in os.environ \
|
|
||||||
or os.environ['NO_SHOW_PKG_DATA_INFO'] != '1':
|
|
||||||
print('\nPackaged data info\n')
|
|
||||||
self.printPackageDataInfo()
|
|
||||||
|
|
||||||
if 'PACKAGES_PREPARE_ONLY' in os.environ \
|
|
||||||
and os.environ['PACKAGES_PREPARE_ONLY'] == '1':
|
|
||||||
print('\nPackage data is ready for merging\n')
|
|
||||||
else:
|
|
||||||
print('\nCreating packages\n')
|
|
||||||
self.package()
|
|
||||||
print('\nCleaning up')
|
|
||||||
self.cleanup()
|
|
||||||
print('Deploy finnished\n')
|
|
||||||
|
|
||||||
def printPackageDataInfo(self):
|
|
||||||
packagedFiles = []
|
|
||||||
|
|
||||||
for root, _, files in os.walk(self.rootInstallDir):
|
|
||||||
for f in files:
|
|
||||||
packagedFiles.append(os.path.join(root, f))
|
|
||||||
|
|
||||||
packagedFiles = sorted(packagedFiles)
|
|
||||||
|
|
||||||
for f in packagedFiles:
|
|
||||||
print(' ' + f)
|
|
||||||
|
|
||||||
def prepare(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def package(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
shutil.rmtree(self.installDir, True)
|
|
|
@ -28,14 +28,16 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import deploy_base
|
from WebcamoidDeployTools import DTDeployBase
|
||||||
import tools.binary_mach
|
from WebcamoidDeployTools import DTQt5
|
||||||
import tools.qt5
|
from WebcamoidDeployTools import DTBinaryMach
|
||||||
|
|
||||||
|
|
||||||
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
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.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, 'Manager'))
|
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
||||||
|
@ -48,8 +50,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
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()
|
||||||
self.binarySolver = tools.binary_mach.DeployToolsBinary()
|
self.binarySolver = DTBinaryMach.MachBinaryTools()
|
||||||
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
self.binarySolver.readExcludes(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')
|
||||||
|
|
|
@ -28,14 +28,16 @@ import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import deploy_base
|
from WebcamoidDeployTools import DTDeployBase
|
||||||
import tools.binary_elf
|
from WebcamoidDeployTools import DTQt5
|
||||||
import tools.qt5
|
from WebcamoidDeployTools import DTBinaryElf
|
||||||
|
|
||||||
|
|
||||||
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
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.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
|
||||||
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', sys.platform)
|
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', sys.platform)
|
||||||
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
||||||
|
@ -52,8 +54,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
elif 'android' in xspec:
|
elif 'android' in xspec:
|
||||||
self.targetSystem = 'android'
|
self.targetSystem = 'android'
|
||||||
|
|
||||||
self.binarySolver = tools.binary_elf.DeployToolsBinary()
|
self.binarySolver = DTBinaryElf.ElfBinaryTools()
|
||||||
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
self.binarySolver.readExcludes(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')
|
||||||
|
|
|
@ -26,14 +26,16 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
import deploy_base
|
from WebcamoidDeployTools import DTDeployBase
|
||||||
import tools.binary_pecoff
|
from WebcamoidDeployTools import DTQt5
|
||||||
import tools.qt5
|
from WebcamoidDeployTools import DTBinaryPecoff
|
||||||
|
|
||||||
|
|
||||||
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
|
||||||
|
self.setRootDir(rootDir)
|
||||||
self.targetSystem = 'posix_windows'
|
self.targetSystem = 'posix_windows'
|
||||||
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/windows')
|
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows')
|
||||||
|
@ -46,8 +48,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0]
|
self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0]
|
||||||
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()
|
||||||
self.binarySolver = tools.binary_pecoff.DeployToolsBinary()
|
self.binarySolver = DTBinaryPecoff.PecoffBinaryTools()
|
||||||
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
self.binarySolver.readExcludes(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')
|
||||||
|
|
|
@ -27,14 +27,16 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
import deploy_base
|
from WebcamoidDeployTools import DTDeployBase
|
||||||
import tools.binary_pecoff
|
from WebcamoidDeployTools import DTQt5
|
||||||
import tools.qt5
|
from WebcamoidDeployTools import DTBinaryPecoff
|
||||||
|
|
||||||
|
|
||||||
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
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.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
|
||||||
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows')
|
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows')
|
||||||
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
self.detectQt(os.path.join(self.buildDir, 'Manager'))
|
||||||
|
@ -46,8 +48,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
|
||||||
self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0]
|
self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0]
|
||||||
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()
|
||||||
self.binarySolver = tools.binary_pecoff.DeployToolsBinary()
|
self.binarySolver = DTBinaryPecoff.PecoffBinaryTools()
|
||||||
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
|
self.binarySolver.readExcludes(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')
|
||||||
|
|
|
@ -1,199 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Webcamoid, webcam capture application.
|
|
||||||
# Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
import tools.utils
|
|
||||||
|
|
||||||
|
|
||||||
class AndroidTools(tools.utils.DeployToolsUtils):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.androidPlatform = ''
|
|
||||||
self.archMap = [('arm64-v8a' , 'aarch64', 'aarch64-linux-android'),
|
|
||||||
('armeabi-v7a', 'arm' , 'arm-linux-androideabi'),
|
|
||||||
('x86' , 'i686' , 'i686-linux-android' ),
|
|
||||||
('x86_64' , 'x86_64' , 'x86_64-linux-android' )]
|
|
||||||
self.androidSDK = ''
|
|
||||||
self.androidNDK = ''
|
|
||||||
self.bundledInLib = []
|
|
||||||
self.qtLibs = []
|
|
||||||
self.localLibs = []
|
|
||||||
|
|
||||||
if 'ANDROID_HOME' in os.environ:
|
|
||||||
self.androidSDK = os.environ['ANDROID_HOME']
|
|
||||||
|
|
||||||
if 'ANDROID_NDK_ROOT' in os.environ:
|
|
||||||
self.androidNDK = os.environ['ANDROID_NDK_ROOT']
|
|
||||||
elif 'ANDROID_NDK' in os.environ:
|
|
||||||
self.androidNDK = os.environ['ANDROID_NDK']
|
|
||||||
|
|
||||||
def detectAndroidPlatform(self, path=''):
|
|
||||||
for makeFile in self.detectMakeFiles(path):
|
|
||||||
with open(makeFile) as f:
|
|
||||||
for line in f:
|
|
||||||
if line.startswith('DESTDIR') and '=' in line:
|
|
||||||
buildPath = os.path.join(path, line.split('=')[1].strip())
|
|
||||||
chunks = [part for part in buildPath.split(os.path.sep) if len(part) > 0]
|
|
||||||
|
|
||||||
if len(chunks) >= 2:
|
|
||||||
self.androidPlatform = chunks[len(chunks) - 2]
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def detectLibPaths(self):
|
|
||||||
if len(self.androidNDK) < 1:
|
|
||||||
return []
|
|
||||||
|
|
||||||
for arch in self.archMap:
|
|
||||||
if self.targetArch == arch[0]:
|
|
||||||
return [os.path.join(self.androidNDK,
|
|
||||||
'toolchains',
|
|
||||||
'llvm',
|
|
||||||
'prebuilt',
|
|
||||||
'linux-x86_64',
|
|
||||||
'sysroot',
|
|
||||||
'usr',
|
|
||||||
'lib',
|
|
||||||
arch[1] + '-linux-android')]
|
|
||||||
|
|
||||||
return []
|
|
||||||
|
|
||||||
def detectBinPaths(self):
|
|
||||||
if len(self.androidNDK) < 1:
|
|
||||||
return []
|
|
||||||
|
|
||||||
for arch in self.archMap:
|
|
||||||
if self.targetArch == arch[0]:
|
|
||||||
binPath = os.path.join(self.androidNDK,
|
|
||||||
'toolchains',
|
|
||||||
'llvm',
|
|
||||||
'prebuilt',
|
|
||||||
'linux-x86_64',
|
|
||||||
arch[2],
|
|
||||||
'bin')
|
|
||||||
|
|
||||||
return [binPath]
|
|
||||||
|
|
||||||
return []
|
|
||||||
|
|
||||||
def fixQtLibs(self):
|
|
||||||
for root, dirs, files in os.walk(self.assetsIntallDir):
|
|
||||||
for f in files:
|
|
||||||
if f.endswith('.so'):
|
|
||||||
srcPath = os.path.join(root, f)
|
|
||||||
relPath = root.replace(self.assetsIntallDir, '')[1:]
|
|
||||||
prefix = 'lib' + relPath.replace(os.path.sep, '_') + '_'
|
|
||||||
lib = ''
|
|
||||||
|
|
||||||
if f.startswith(prefix):
|
|
||||||
lib = f
|
|
||||||
else:
|
|
||||||
lib = prefix + f
|
|
||||||
|
|
||||||
dstPath = os.path.join(self.libInstallDir, lib)
|
|
||||||
print(' {} -> {}'.format(srcPath, dstPath))
|
|
||||||
self.move(srcPath, dstPath)
|
|
||||||
self.bundledInLib += [(lib, os.path.join(relPath, f))]
|
|
||||||
|
|
||||||
def libBaseName(self, lib):
|
|
||||||
basename = os.path.basename(lib)
|
|
||||||
|
|
||||||
return basename[3: len(basename) - 3]
|
|
||||||
|
|
||||||
def fixLibsXml(self):
|
|
||||||
bundledInAssets = []
|
|
||||||
assetsDir = os.path.join(self.rootInstallDir, 'assets')
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(assetsDir):
|
|
||||||
for f in files:
|
|
||||||
srcPath = os.path.join(root.replace(assetsDir, '')[1:], f)
|
|
||||||
dstPath = os.path.sep.join(srcPath.split(os.path.sep)[1:])
|
|
||||||
|
|
||||||
if (len(dstPath) > 0):
|
|
||||||
bundledInAssets += [(srcPath, dstPath)]
|
|
||||||
|
|
||||||
libsXml = os.path.join(self.rootInstallDir, 'res', 'values', 'libs.xml')
|
|
||||||
libsXmlTemp = os.path.join(self.rootInstallDir, 'res', 'values', 'libsTemp.xml')
|
|
||||||
|
|
||||||
tree = ET.parse(libsXml)
|
|
||||||
root = tree.getroot()
|
|
||||||
oldFeatures = set()
|
|
||||||
oldPermissions = set()
|
|
||||||
resources = {}
|
|
||||||
|
|
||||||
for array in root:
|
|
||||||
if not array.attrib['name'] in resources:
|
|
||||||
resources[array.attrib['name']] = set()
|
|
||||||
|
|
||||||
for item in array:
|
|
||||||
if item.text:
|
|
||||||
lib = item.text.strip()
|
|
||||||
|
|
||||||
if len(lib) > 0:
|
|
||||||
lib = '<item>{}</item>'.format(lib)
|
|
||||||
resources[array.attrib['name']].add(lib)
|
|
||||||
|
|
||||||
qtLibs = set(['<item>{};{}</item>'.format(self.targetArch, self.libBaseName(lib)) for lib in self.qtLibs])
|
|
||||||
|
|
||||||
if 'qt_libs' in resources:
|
|
||||||
qtLibs -= resources['qt_libs']
|
|
||||||
|
|
||||||
qtLibs = '\n'.join(sorted(list(qtLibs)))
|
|
||||||
bundledInLib = set(['<item>{}:{}</item>'.format(lib[0], lib[1]) for lib in self.bundledInLib])
|
|
||||||
|
|
||||||
if 'bundled_in_lib' in resources:
|
|
||||||
bundledInLib -= resources['bundled_in_lib']
|
|
||||||
|
|
||||||
bundledInLib = '\n'.join(sorted(list(bundledInLib)))
|
|
||||||
bundledInAssets = set(['<item>{}:{}</item>'.format(lib[0], lib[1]) for lib in bundledInAssets])
|
|
||||||
|
|
||||||
if 'bundled_in_assets' in resources:
|
|
||||||
bundledInAssets -= resources['bundled_in_assets']
|
|
||||||
|
|
||||||
bundledInAssets = '\n'.join(sorted(list(bundledInAssets)))
|
|
||||||
|
|
||||||
localLibs = sorted(list(set(self.localLibs)))
|
|
||||||
localLibs = set(['<item>{};{}</item>'.format(self.targetArch, ':'.join(localLibs)) for lib in localLibs])
|
|
||||||
|
|
||||||
if 'load_local_libs' in resources:
|
|
||||||
localLibs -= resources['load_local_libs']
|
|
||||||
|
|
||||||
localLibs = '\n'.join(sorted(list(localLibs)))
|
|
||||||
|
|
||||||
replace = {'<!-- %%INSERT_EXTRA_LIBS%% -->' : '',
|
|
||||||
'<!-- %%INSERT_QT_LIBS%% -->' : qtLibs,
|
|
||||||
'<!-- %%INSERT_BUNDLED_IN_LIB%% -->' : bundledInLib,
|
|
||||||
'<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->': bundledInAssets,
|
|
||||||
'<!-- %%INSERT_LOCAL_LIBS%% -->' : localLibs}
|
|
||||||
|
|
||||||
with open(libsXml) as inFile:
|
|
||||||
with open(libsXmlTemp, 'w') as outFile:
|
|
||||||
for line in inFile:
|
|
||||||
for key in replace:
|
|
||||||
line = line.replace(key, replace[key])
|
|
||||||
|
|
||||||
outFile.write(line)
|
|
||||||
|
|
||||||
os.remove(libsXml)
|
|
||||||
shutil.move(libsXmlTemp, libsXml)
|
|
|
@ -1,169 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import subprocess # nosec
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
import tools
|
|
||||||
|
|
||||||
|
|
||||||
class DeployToolsBinary(tools.utils.DeployToolsUtils):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.detectStrip()
|
|
||||||
self.excludes = []
|
|
||||||
|
|
||||||
def isValid(self, path):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def find(self, path):
|
|
||||||
binaries = []
|
|
||||||
|
|
||||||
for root, _, files in os.walk(path):
|
|
||||||
for f in files:
|
|
||||||
binaryPath = os.path.join(root, f)
|
|
||||||
|
|
||||||
if not os.path.islink(binaryPath) and self.isValid(binaryPath):
|
|
||||||
binaries.append(binaryPath)
|
|
||||||
|
|
||||||
return binaries
|
|
||||||
|
|
||||||
def dump(self, binary):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def dependencies(self, binary):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def allDependencies(self, binary):
|
|
||||||
deps = self.dependencies(binary)
|
|
||||||
solved = set()
|
|
||||||
|
|
||||||
while len(deps) > 0:
|
|
||||||
dep = deps.pop()
|
|
||||||
|
|
||||||
for binDep in self.dependencies(dep):
|
|
||||||
if binDep != dep and not binDep in solved:
|
|
||||||
deps.append(binDep)
|
|
||||||
|
|
||||||
if self.system == 'mac':
|
|
||||||
i = dep.rfind('.framework/')
|
|
||||||
|
|
||||||
if i >= 0:
|
|
||||||
dep = dep[: i] + '.framework'
|
|
||||||
|
|
||||||
solved.add(dep)
|
|
||||||
|
|
||||||
return solved
|
|
||||||
|
|
||||||
def scanDependencies(self, path):
|
|
||||||
deps = set()
|
|
||||||
|
|
||||||
for binPath in self.find(path):
|
|
||||||
for dep in self.allDependencies(binPath):
|
|
||||||
deps.add(dep)
|
|
||||||
|
|
||||||
return sorted(deps)
|
|
||||||
|
|
||||||
def name(self, binary):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def detectStrip(self):
|
|
||||||
self.stripBin = self.whereBin('strip.exe' if self.system == 'windows' else 'strip')
|
|
||||||
|
|
||||||
def strip(self, binary):
|
|
||||||
if self.stripBin == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
process = subprocess.Popen([self.stripBin, binary], # nosec
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
def stripSymbols(self, path):
|
|
||||||
threads = []
|
|
||||||
|
|
||||||
for binary in self.find(path):
|
|
||||||
thread = threading.Thread(target=self.strip, args=(binary,))
|
|
||||||
threads.append(thread)
|
|
||||||
|
|
||||||
while threading.active_count() >= self.njobs:
|
|
||||||
time.sleep(0.25)
|
|
||||||
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
for thread in threads:
|
|
||||||
thread.join()
|
|
||||||
|
|
||||||
def readExcludeList(self, excludeList):
|
|
||||||
self.excludes = []
|
|
||||||
|
|
||||||
if os.path.exists(excludeList):
|
|
||||||
with open(excludeList) as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if len(line) > 0 and line[0] != '#':
|
|
||||||
i = line.find('#')
|
|
||||||
|
|
||||||
if i >= 0:
|
|
||||||
line = line[: i]
|
|
||||||
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if len(line) > 0:
|
|
||||||
self.excludes.append(line)
|
|
||||||
|
|
||||||
def isExcluded(self, path):
|
|
||||||
for exclude in self.excludes:
|
|
||||||
if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows':
|
|
||||||
path = path.lower().replace('\\', '/')
|
|
||||||
exclude = exclude.lower()
|
|
||||||
|
|
||||||
if re.fullmatch(exclude, path):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def resetFilePermissions(self, rootPath, binariesPath):
|
|
||||||
for root, dirs, files in os.walk(rootPath):
|
|
||||||
for d in dirs:
|
|
||||||
permissions = 0o755
|
|
||||||
path = os.path.join(root, d)
|
|
||||||
|
|
||||||
if self.system == 'mac':
|
|
||||||
os.chmod(path, permissions, follow_symlinks=False)
|
|
||||||
else:
|
|
||||||
os.chmod(path, permissions)
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
permissions = 0o644
|
|
||||||
path = os.path.join(root, f)
|
|
||||||
|
|
||||||
if root == binariesPath and self.isValid(path):
|
|
||||||
permissions = 0o744
|
|
||||||
|
|
||||||
if self.system == 'mac':
|
|
||||||
os.chmod(path, permissions, follow_symlinks=False)
|
|
||||||
else:
|
|
||||||
os.chmod(path, permissions)
|
|
|
@ -1,345 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import fnmatch
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import tools.binary
|
|
||||||
|
|
||||||
|
|
||||||
class DeployToolsBinary(tools.binary.DeployToolsBinary):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.ldLibraryPath = os.environ['LD_LIBRARY_PATH'].split(':') if 'LD_LIBRARY_PATH' in os.environ else []
|
|
||||||
self.libsSeachPaths = self.readLdconf() \
|
|
||||||
+ ['/usr/lib',
|
|
||||||
'/usr/lib64',
|
|
||||||
'/lib',
|
|
||||||
'/lib64',
|
|
||||||
'/usr/local/lib',
|
|
||||||
'/usr/local/lib64']
|
|
||||||
self.emCodes = {3 : '386',
|
|
||||||
40 : 'ARM',
|
|
||||||
62 : 'X86_64',
|
|
||||||
183: 'AARCH64'}
|
|
||||||
|
|
||||||
def readLdconf(self, ldconf='/etc/ld.so.conf'):
|
|
||||||
if not os.path.exists(ldconf):
|
|
||||||
return []
|
|
||||||
|
|
||||||
confDir = os.path.dirname(ldconf)
|
|
||||||
libpaths = []
|
|
||||||
|
|
||||||
with open(ldconf) as f:
|
|
||||||
for line in f:
|
|
||||||
i = line.find('#')
|
|
||||||
|
|
||||||
if i == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if i >= 0:
|
|
||||||
line = line[: i]
|
|
||||||
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if len(line) < 1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if line.startswith('include'):
|
|
||||||
conf = line.split()[1]
|
|
||||||
|
|
||||||
if not conf.startswith('/'):
|
|
||||||
conf = os.path.join(confDir, conf)
|
|
||||||
|
|
||||||
dirname = os.path.dirname(conf)
|
|
||||||
|
|
||||||
if os.path.exists(dirname):
|
|
||||||
for f in os.listdir(dirname):
|
|
||||||
path = os.path.join(dirname, f)
|
|
||||||
|
|
||||||
if fnmatch.fnmatch(path, conf):
|
|
||||||
libpaths += self.readLdconf(path)
|
|
||||||
else:
|
|
||||||
libpaths.append(line)
|
|
||||||
|
|
||||||
return libpaths
|
|
||||||
|
|
||||||
def isValid(self, path):
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
return f.read(4) == b'\x7fELF'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def readString(f):
|
|
||||||
s = b''
|
|
||||||
|
|
||||||
while True:
|
|
||||||
c = f.read(1)
|
|
||||||
|
|
||||||
if c == b'\x00':
|
|
||||||
break
|
|
||||||
|
|
||||||
s += c
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def readNumber(f, arch):
|
|
||||||
if arch == '32bits':
|
|
||||||
return struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
return struct.unpack('Q', f.read(8))[0]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def readDynamicEntry(f, arch):
|
|
||||||
if arch == '32bits':
|
|
||||||
return struct.unpack('iI', f.read(8))
|
|
||||||
|
|
||||||
return struct.unpack('qQ', f.read(16))
|
|
||||||
|
|
||||||
# https://refspecs.linuxfoundation.org/lsb.shtml (See Core, Generic)
|
|
||||||
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
|
||||||
def dump(self, binary):
|
|
||||||
# ELF file magic
|
|
||||||
ELFMAGIC = b'\x7fELF'
|
|
||||||
|
|
||||||
# Sections
|
|
||||||
SHT_STRTAB = 0x3
|
|
||||||
SHT_DYNAMIC = 0x6
|
|
||||||
|
|
||||||
# Dynamic section entries
|
|
||||||
DT_NULL = 0
|
|
||||||
DT_NEEDED = 1
|
|
||||||
DT_RPATH = 15
|
|
||||||
DT_RUNPATH = 0x1d
|
|
||||||
|
|
||||||
with open(binary, 'rb') as f:
|
|
||||||
# Read magic signature.
|
|
||||||
magic = f.read(4)
|
|
||||||
|
|
||||||
if magic != ELFMAGIC:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# Read the data structure of the file.
|
|
||||||
eiClass = '32bits' if struct.unpack('B', f.read(1))[0] == 1 else '64bits'
|
|
||||||
|
|
||||||
# Read machine code.
|
|
||||||
f.seek(0x12, os.SEEK_SET)
|
|
||||||
machine = struct.unpack('H', f.read(2))[0]
|
|
||||||
|
|
||||||
# Get a pointer to the sections table.
|
|
||||||
sectionHeaderTable = 0
|
|
||||||
|
|
||||||
if eiClass == '32bits':
|
|
||||||
f.seek(0x20, os.SEEK_SET)
|
|
||||||
sectionHeaderTable = self.readNumber(f, eiClass)
|
|
||||||
f.seek(0x30, os.SEEK_SET)
|
|
||||||
else:
|
|
||||||
f.seek(0x28, os.SEEK_SET)
|
|
||||||
sectionHeaderTable = self.readNumber(f, eiClass)
|
|
||||||
f.seek(0x3c, os.SEEK_SET)
|
|
||||||
|
|
||||||
# Read the number of sections.
|
|
||||||
nSections = struct.unpack('H', f.read(2))[0]
|
|
||||||
|
|
||||||
# Read the index of the string table that stores sections names.
|
|
||||||
shstrtabIndex = struct.unpack('H', f.read(2))[0]
|
|
||||||
|
|
||||||
# Read sections.
|
|
||||||
f.seek(sectionHeaderTable, os.SEEK_SET)
|
|
||||||
neededPtr = []
|
|
||||||
rpathsPtr = []
|
|
||||||
runpathsPtr = []
|
|
||||||
strtabs = []
|
|
||||||
shstrtab = []
|
|
||||||
|
|
||||||
for section in range(nSections):
|
|
||||||
sectionStart = f.tell()
|
|
||||||
|
|
||||||
# Read the a pointer to the virtual address in the string table
|
|
||||||
# that contains the name of this section.
|
|
||||||
sectionName = struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
# Read the type of this section.
|
|
||||||
sectionType = struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
# Read the virtual address of this section.
|
|
||||||
f.seek(sectionStart + (0x0c if eiClass == '32bits' else 0x10), os.SEEK_SET)
|
|
||||||
shAddr = self.readNumber(f, eiClass)
|
|
||||||
|
|
||||||
# Read the offset in file to this section.
|
|
||||||
shOffset = self.readNumber(f, eiClass)
|
|
||||||
f.seek(shOffset, os.SEEK_SET)
|
|
||||||
|
|
||||||
if sectionType == SHT_DYNAMIC:
|
|
||||||
# Read dynamic sections.
|
|
||||||
while True:
|
|
||||||
# Read dynamic entries.
|
|
||||||
dTag, dVal = self.readDynamicEntry(f, eiClass)
|
|
||||||
|
|
||||||
if dTag == DT_NULL:
|
|
||||||
# End of dynamic sections.
|
|
||||||
break
|
|
||||||
elif dTag == DT_NEEDED:
|
|
||||||
# Dynamically imported libraries.
|
|
||||||
neededPtr.append(dVal)
|
|
||||||
elif dTag == DT_RPATH:
|
|
||||||
# RPATHs.
|
|
||||||
rpathsPtr.append(dVal)
|
|
||||||
elif dTag == DT_RUNPATH:
|
|
||||||
# RUNPATHs.
|
|
||||||
runpathsPtr.append(dVal)
|
|
||||||
elif sectionType == SHT_STRTAB:
|
|
||||||
# Read string tables.
|
|
||||||
if section == shstrtabIndex:
|
|
||||||
# We found the string table that stores sections names.
|
|
||||||
shstrtab = [shAddr, shOffset]
|
|
||||||
else:
|
|
||||||
# Save string tables for later usage.
|
|
||||||
strtabs += [[sectionName, shAddr, shOffset]]
|
|
||||||
|
|
||||||
# Move to next section.
|
|
||||||
f.seek(sectionStart + (0x28 if eiClass == '32bits' else 0x40), os.SEEK_SET)
|
|
||||||
|
|
||||||
# Libraries names and RUNPATHs are located in '.dynstr' table.
|
|
||||||
strtab = []
|
|
||||||
|
|
||||||
for tab in strtabs:
|
|
||||||
f.seek(tab[0] - shstrtab[0] + shstrtab[1], os.SEEK_SET)
|
|
||||||
|
|
||||||
if self.readString(f) == b'.dynstr':
|
|
||||||
strtab = tab
|
|
||||||
|
|
||||||
# Read dynamically imported libraries.
|
|
||||||
needed = set()
|
|
||||||
|
|
||||||
for lib in neededPtr:
|
|
||||||
f.seek(lib + strtab[2], os.SEEK_SET)
|
|
||||||
needed.add(self.readString(f).decode(sys.getdefaultencoding()))
|
|
||||||
|
|
||||||
# Read RPATHs
|
|
||||||
rpaths = set()
|
|
||||||
|
|
||||||
for path in rpathsPtr:
|
|
||||||
f.seek(path + strtab[2], os.SEEK_SET)
|
|
||||||
rpaths.add(self.readString(f).decode(sys.getdefaultencoding()))
|
|
||||||
|
|
||||||
# Read RUNPATHs
|
|
||||||
runpaths = set()
|
|
||||||
|
|
||||||
for path in runpathsPtr:
|
|
||||||
f.seek(path + strtab[2], os.SEEK_SET)
|
|
||||||
runpaths.add(self.readString(f).decode(sys.getdefaultencoding()))
|
|
||||||
|
|
||||||
return {'machine': machine,
|
|
||||||
'imports': needed,
|
|
||||||
'rpath': rpaths,
|
|
||||||
'runpath': runpaths}
|
|
||||||
|
|
||||||
return {}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def readRpaths(elfInfo, binDir):
|
|
||||||
rpaths = []
|
|
||||||
runpaths = []
|
|
||||||
|
|
||||||
# http://amir.rachum.com/blog/2016/09/17/shared-libraries/
|
|
||||||
for rpath in ['rpath', 'runpath']:
|
|
||||||
for path in elfInfo[rpath]:
|
|
||||||
if '$ORIGIN' in path:
|
|
||||||
path = path.replace('$ORIGIN', binDir)
|
|
||||||
|
|
||||||
if not path.startswith('/'):
|
|
||||||
path = os.path.join(binDir, path)
|
|
||||||
|
|
||||||
path = os.path.normpath(path)
|
|
||||||
|
|
||||||
if rpath == 'rpath':
|
|
||||||
rpaths.append(path)
|
|
||||||
else:
|
|
||||||
runpaths.append(path)
|
|
||||||
|
|
||||||
return rpaths, runpaths
|
|
||||||
|
|
||||||
def libPath(self, lib, machine, rpaths, runpaths):
|
|
||||||
# man ld.so
|
|
||||||
searchPaths = rpaths \
|
|
||||||
+ self.ldLibraryPath \
|
|
||||||
+ runpaths \
|
|
||||||
+ self.libsSeachPaths
|
|
||||||
|
|
||||||
for libdir in searchPaths:
|
|
||||||
path = os.path.join(libdir, lib)
|
|
||||||
|
|
||||||
if os.path.exists(path):
|
|
||||||
depElfInfo = self.dump(path)
|
|
||||||
|
|
||||||
if depElfInfo:
|
|
||||||
if 'machine' in depElfInfo and (machine == 0 or depElfInfo['machine'] == machine):
|
|
||||||
return path
|
|
||||||
elif 'links' in depElfInfo and len(depElfInfo['links']) > 0:
|
|
||||||
return path
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def dependencies(self, binary):
|
|
||||||
elfInfo = self.dump(binary)
|
|
||||||
|
|
||||||
if not elfInfo:
|
|
||||||
return []
|
|
||||||
|
|
||||||
rpaths, runpaths = self.readRpaths(elfInfo, os.path.dirname(binary))
|
|
||||||
libs = []
|
|
||||||
deps = []
|
|
||||||
|
|
||||||
if 'imports' in elfInfo:
|
|
||||||
deps = elfInfo['imports']
|
|
||||||
elif 'links' in elfInfo:
|
|
||||||
deps = elfInfo['links']
|
|
||||||
|
|
||||||
machine = 0
|
|
||||||
|
|
||||||
if 'machine' in elfInfo:
|
|
||||||
machine = elfInfo['machine']
|
|
||||||
|
|
||||||
for lib in deps:
|
|
||||||
libpath = self.libPath(lib, machine, rpaths, runpaths)
|
|
||||||
|
|
||||||
if len(libpath) > 0 and not self.isExcluded(libpath):
|
|
||||||
libs.append(libpath)
|
|
||||||
|
|
||||||
return libs
|
|
||||||
|
|
||||||
def name(self, binary):
|
|
||||||
dep = os.path.basename(binary)[3:]
|
|
||||||
|
|
||||||
return dep[: dep.find('.')]
|
|
||||||
|
|
||||||
def machineEMCode(self, binary):
|
|
||||||
info = self.dump(binary)
|
|
||||||
|
|
||||||
if 'machine' in info:
|
|
||||||
if info['machine'] in self.emCodes:
|
|
||||||
return self.emCodes[info['machine']]
|
|
||||||
|
|
||||||
return 'UNKNOWN'
|
|
|
@ -1,182 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import tools.binary
|
|
||||||
|
|
||||||
|
|
||||||
class DeployToolsBinary(tools.binary.DeployToolsBinary):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
# 32 bits magic number.
|
|
||||||
self.MH_MAGIC = 0xfeedface # Native endian
|
|
||||||
self.MH_CIGAM = 0xcefaedfe # Reverse endian
|
|
||||||
|
|
||||||
# 64 bits magic number.
|
|
||||||
self.MH_MAGIC_64 = 0xfeedfacf # Native endian
|
|
||||||
self.MH_CIGAM_64 = 0xcffaedfe # Reverse endian
|
|
||||||
|
|
||||||
def isValid(self, path):
|
|
||||||
try:
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
# Read magic number.
|
|
||||||
magic = struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
if magic == self.MH_MAGIC \
|
|
||||||
or magic == self.MH_CIGAM \
|
|
||||||
or magic == self.MH_MAGIC_64 \
|
|
||||||
or magic == self.MH_CIGAM_64:
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
# https://github.com/aidansteele/osx-abi-macho-file-format-reference
|
|
||||||
def dump(self, binary):
|
|
||||||
# Commands definitions
|
|
||||||
LC_REQ_DYLD = 0x80000000
|
|
||||||
LC_LOAD_DYLIB = 0xc
|
|
||||||
LC_RPATH = 0x1c | LC_REQ_DYLD
|
|
||||||
LC_ID_DYLIB = 0xd
|
|
||||||
|
|
||||||
dylibImports = []
|
|
||||||
rpaths = []
|
|
||||||
dylibId = ''
|
|
||||||
|
|
||||||
with open(binary, 'rb') as f:
|
|
||||||
# Read magic number.
|
|
||||||
magic = struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
if magic == self.MH_MAGIC or magic == self.MH_CIGAM:
|
|
||||||
is32bits = True
|
|
||||||
elif magic == self.MH_MAGIC_64 or magic == self.MH_CIGAM_64:
|
|
||||||
is32bits = False
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# Read number of commands.
|
|
||||||
f.seek(12, os.SEEK_CUR)
|
|
||||||
ncmds = struct.unpack('I', f.read(4))[0]
|
|
||||||
|
|
||||||
# Move to load commands
|
|
||||||
f.seek(8 if is32bits else 12, os.SEEK_CUR)
|
|
||||||
|
|
||||||
for _ in range(ncmds):
|
|
||||||
# Read a load command and store it's position in the file.
|
|
||||||
loadCommandStart = f.tell()
|
|
||||||
loadCommand = struct.unpack('II', f.read(8))
|
|
||||||
|
|
||||||
# If the command list a library
|
|
||||||
if loadCommand[0] in [LC_LOAD_DYLIB, LC_RPATH, LC_ID_DYLIB]:
|
|
||||||
# Save the position of the next command.
|
|
||||||
nextCommand = f.tell() + loadCommand[1] - 8
|
|
||||||
|
|
||||||
# Move to the string
|
|
||||||
f.seek(loadCommandStart + struct.unpack('I', f.read(4))[0], os.SEEK_SET)
|
|
||||||
dylib = b''
|
|
||||||
|
|
||||||
# Read string until null character.
|
|
||||||
while True:
|
|
||||||
c = f.read(1)
|
|
||||||
|
|
||||||
if c == b'\x00':
|
|
||||||
break
|
|
||||||
|
|
||||||
dylib += c
|
|
||||||
s = dylib.decode(sys.getdefaultencoding())
|
|
||||||
|
|
||||||
if loadCommand[0] == LC_LOAD_DYLIB:
|
|
||||||
dylibImports.append(s)
|
|
||||||
elif loadCommand[0] == LC_RPATH:
|
|
||||||
rpaths.append(s)
|
|
||||||
elif loadCommand[0] == LC_ID_DYLIB:
|
|
||||||
dylibId = s
|
|
||||||
|
|
||||||
f.seek(nextCommand, os.SEEK_SET)
|
|
||||||
else:
|
|
||||||
f.seek(loadCommand[1] - 8, os.SEEK_CUR)
|
|
||||||
|
|
||||||
return {'imports': dylibImports, 'rpaths': rpaths, 'id': dylibId}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def solveRefpath(path):
|
|
||||||
if not path.startswith('@'):
|
|
||||||
return path
|
|
||||||
|
|
||||||
searchPaths = []
|
|
||||||
|
|
||||||
if 'DYLD_LIBRARY_PATH' in os.environ:
|
|
||||||
searchPaths += os.environ['DYLD_LIBRARY_PATH'].split(':')
|
|
||||||
|
|
||||||
if 'DYLD_FRAMEWORK_PATH' in os.environ:
|
|
||||||
searchPaths += os.environ['DYLD_FRAMEWORK_PATH'].split(':')
|
|
||||||
|
|
||||||
if path.endswith('.dylib'):
|
|
||||||
dep = os.path.basename(path)
|
|
||||||
else:
|
|
||||||
i = path.rfind(os.sep, 0, path.rfind('.framework'))
|
|
||||||
dep = path[i + 1:]
|
|
||||||
|
|
||||||
for fpath in searchPaths:
|
|
||||||
realPath = os.path.join(fpath, dep)
|
|
||||||
|
|
||||||
if os.path.exists(realPath):
|
|
||||||
return realPath
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def dependencies(self, binary):
|
|
||||||
machInfo = self.dump(binary)
|
|
||||||
|
|
||||||
if not machInfo:
|
|
||||||
return []
|
|
||||||
|
|
||||||
libs = []
|
|
||||||
|
|
||||||
for mach in machInfo['imports']:
|
|
||||||
mach = self.solveRefpath(mach)
|
|
||||||
|
|
||||||
if mach == '' or self.isExcluded(mach) or not os.path.exists(mach):
|
|
||||||
continue
|
|
||||||
|
|
||||||
dirName = os.path.dirname(mach)
|
|
||||||
dirName = os.path.realpath(dirName)
|
|
||||||
baseName = os.path.basename(mach)
|
|
||||||
libs.append(os.path.join(dirName, baseName))
|
|
||||||
|
|
||||||
return libs
|
|
||||||
|
|
||||||
def name(self, binary):
|
|
||||||
dep = os.path.basename(binary)
|
|
||||||
i = dep.find('.')
|
|
||||||
|
|
||||||
if i >= 0:
|
|
||||||
dep = dep[: dep.find('.')]
|
|
||||||
|
|
||||||
if 'Qt' in dep and not 'Qt5' in dep:
|
|
||||||
dep = dep.replace('Qt', 'Qt5')
|
|
||||||
|
|
||||||
return dep
|
|
|
@ -1,179 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import mimetypes
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import tools.binary
|
|
||||||
|
|
||||||
|
|
||||||
class DeployToolsBinary(tools.binary.DeployToolsBinary):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
def isValid(self, path):
|
|
||||||
mimetype, _ = mimetypes.guess_type(path)
|
|
||||||
|
|
||||||
if mimetype == 'application/x-msdownload':
|
|
||||||
return True
|
|
||||||
|
|
||||||
if mimetype != 'application/octet-stream':
|
|
||||||
return False
|
|
||||||
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
if f.read(2) != b'MZ':
|
|
||||||
return []
|
|
||||||
|
|
||||||
f.seek(0x3c, os.SEEK_SET)
|
|
||||||
peHeaderOffset = struct.unpack('I', f.read(4))
|
|
||||||
f.seek(peHeaderOffset[0], os.SEEK_SET)
|
|
||||||
peSignatue = f.read(4)
|
|
||||||
|
|
||||||
if peSignatue != b'PE\x00\x00':
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx
|
|
||||||
# https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
|
|
||||||
def dump(self, binary):
|
|
||||||
dllImports = set()
|
|
||||||
|
|
||||||
if not os.path.exists(binary) or not os.path.isfile(binary):
|
|
||||||
return dllImports
|
|
||||||
|
|
||||||
with open(binary, 'rb') as f:
|
|
||||||
# Check DOS header signature.
|
|
||||||
if f.read(2) != b'MZ':
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Move to COFF header.
|
|
||||||
f.seek(0x3c, os.SEEK_SET)
|
|
||||||
peHeaderOffset = struct.unpack('I', f.read(4))
|
|
||||||
f.seek(peHeaderOffset[0], os.SEEK_SET)
|
|
||||||
peSignatue = f.read(4)
|
|
||||||
|
|
||||||
# Check COFF header signature.
|
|
||||||
if peSignatue != b'PE\x00\x00':
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Read COFF header.
|
|
||||||
coffHeader = struct.unpack('HHIIIHH', f.read(20))
|
|
||||||
nSections = coffHeader[1]
|
|
||||||
sectionTablePos = coffHeader[5] + f.tell()
|
|
||||||
|
|
||||||
# Read magic signature in standard COFF fields.
|
|
||||||
peType = 'PE32' if f.read(2) == b'\x0b\x01' else 'PE32+'
|
|
||||||
|
|
||||||
# Move to data directories.
|
|
||||||
f.seek(102 if peType == 'PE32' else 118, os.SEEK_CUR)
|
|
||||||
|
|
||||||
# Read the import table.
|
|
||||||
importTablePos, importTableSize = struct.unpack('II', f.read(8))
|
|
||||||
|
|
||||||
# Move to Sections table.
|
|
||||||
f.seek(sectionTablePos, os.SEEK_SET)
|
|
||||||
sections = []
|
|
||||||
idataTablePhysical = -1
|
|
||||||
|
|
||||||
# Search for 'idata' section.
|
|
||||||
for _ in range(nSections):
|
|
||||||
# Read section.
|
|
||||||
section = struct.unpack('8pIIIIIIHHI', f.read(40))
|
|
||||||
sectionName = section[0].replace(b'\x00', b'')
|
|
||||||
|
|
||||||
# Save a reference to the sections.
|
|
||||||
sections += [section]
|
|
||||||
|
|
||||||
if sectionName == b'idata' or sectionName == b'rdata':
|
|
||||||
idataTablePhysical = section[4]
|
|
||||||
|
|
||||||
# If import table was defined calculate it's position in
|
|
||||||
# the file in relation to the address given by 'idata'.
|
|
||||||
if importTableSize > 0:
|
|
||||||
idataTablePhysical += importTablePos - section[2]
|
|
||||||
|
|
||||||
if idataTablePhysical < 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Move to 'idata' section.
|
|
||||||
f.seek(idataTablePhysical, os.SEEK_SET)
|
|
||||||
dllList = set()
|
|
||||||
|
|
||||||
# Read 'idata' directory table.
|
|
||||||
while True:
|
|
||||||
# Read DLL entries.
|
|
||||||
try:
|
|
||||||
dllImport = struct.unpack('IIIII', f.read(20))
|
|
||||||
except:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Null directory entry.
|
|
||||||
if dllImport[0] | dllImport[1] | dllImport[2] | dllImport[3] | dllImport[4] == 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Locate where is located the DLL name in relation to the
|
|
||||||
# sections.
|
|
||||||
for section in sections:
|
|
||||||
if dllImport[3] >= section[2] \
|
|
||||||
and dllImport[3] < section[1] + section[2]:
|
|
||||||
dllList.add(dllImport[3] - section[2] + section[4])
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
for dll in dllList:
|
|
||||||
# Move to DLL name.
|
|
||||||
f.seek(dll, os.SEEK_SET)
|
|
||||||
dllName = b''
|
|
||||||
|
|
||||||
# Read string until null character.
|
|
||||||
while True:
|
|
||||||
c = f.read(1)
|
|
||||||
|
|
||||||
if c == b'\x00':
|
|
||||||
break
|
|
||||||
|
|
||||||
dllName += c
|
|
||||||
|
|
||||||
try:
|
|
||||||
dllImports.add(dllName.decode(sys.getdefaultencoding()))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return dllImports
|
|
||||||
|
|
||||||
def dependencies(self, binary):
|
|
||||||
deps = []
|
|
||||||
|
|
||||||
for dep in self.dump(binary):
|
|
||||||
depPath = self.whereBin(dep)
|
|
||||||
|
|
||||||
if len(depPath) > 0 and not self.isExcluded(depPath):
|
|
||||||
deps.append(depPath)
|
|
||||||
|
|
||||||
return deps
|
|
||||||
|
|
||||||
def name(self, binary):
|
|
||||||
dep = os.path.basename(binary)
|
|
||||||
|
|
||||||
return dep[: dep.find('.')]
|
|
|
@ -1,2 +0,0 @@
|
||||||
C:/Windows/System32/.*
|
|
||||||
C:/Program Files/.*
|
|
|
@ -1,2 +0,0 @@
|
||||||
/usr/lib/.*
|
|
||||||
/System/Library/Frameworks/.*
|
|
|
@ -1,110 +0,0 @@
|
||||||
# VDSO
|
|
||||||
(.*/)*ld-linux.so.2
|
|
||||||
(.*/)*ld-linux-x86-64.so.2
|
|
||||||
|
|
||||||
# Glibc
|
|
||||||
(.*/)*libc.so.[0-9]+
|
|
||||||
(.*/)*libdl.so.[0-9]+
|
|
||||||
(.*/)*libm.so.[0-9]+
|
|
||||||
(.*/)*libmvec.so.[0-9]+
|
|
||||||
(.*/)*libpthread.so.[0-9]+
|
|
||||||
(.*/)*libresolv.so.[0-9]+
|
|
||||||
(.*/)*librt.so.[0-9]+
|
|
||||||
|
|
||||||
# GCC
|
|
||||||
(.*/)*libgcc_s.so.[0-9]+
|
|
||||||
(.*/)*libgomp.so.[0-9]+
|
|
||||||
(.*/)*libstdc\+\+.so.[0-9]+
|
|
||||||
|
|
||||||
# Core libraries
|
|
||||||
(.*/)*libSM.so.6
|
|
||||||
(.*/)*libblkid.so.1
|
|
||||||
(.*/)*libcap.so.2
|
|
||||||
(.*/)*libcom_err.so.2
|
|
||||||
(.*/)*libcrypto.so.1.0.0
|
|
||||||
(.*/)*libdb-5.3.so
|
|
||||||
(.*/)*libdbus-1.so.3
|
|
||||||
(.*/)*libexpat.so.1
|
|
||||||
(.*/)*libfontconfig.so.1
|
|
||||||
(.*/)*libfreetype.so.6
|
|
||||||
(.*/)*libgcrypt.so.20
|
|
||||||
(.*/)*libgmp.so.10
|
|
||||||
(.*/)*libgpg-error.so.0
|
|
||||||
(.*/)*libgssapi_krb5.so.2
|
|
||||||
(.*/)*libharfbuzz.so.0
|
|
||||||
(.*/)*libk5crypto.so.3
|
|
||||||
(.*/)*libkeyutils.so.1
|
|
||||||
(.*/)*libkrb5.so.3
|
|
||||||
(.*/)*libkrb5support.so.0
|
|
||||||
(.*/)*liblz4.so.1
|
|
||||||
(.*/)*liblzma.so.5
|
|
||||||
(.*/)*libmount.so.1
|
|
||||||
(.*/)*libpcre.so.[0-9]+$
|
|
||||||
(.*/)*libpcre16.so.0
|
|
||||||
(.*/)*libssh2.so.1
|
|
||||||
(.*/)*libssl.so.1.0.0
|
|
||||||
(.*/)*libtasn1.so.6
|
|
||||||
(.*/)*libusb-1.0.so.0
|
|
||||||
(.*/)*libuuid.so.1
|
|
||||||
(.*/)*libz.so.1
|
|
||||||
|
|
||||||
# Glib2
|
|
||||||
(.*/)*libgio-2.0.so.0
|
|
||||||
(.*/)*libglib-2.0.so.0
|
|
||||||
(.*/)*libgmodule-2.0.so.0
|
|
||||||
(.*/)*libgobject-2.0.so.0
|
|
||||||
|
|
||||||
# X11
|
|
||||||
(.*/)*libX11-xcb.so.[0-9]+
|
|
||||||
(.*/)*libX11.so.[0-9]+
|
|
||||||
(.*/)*libXau.so.[0-9]+
|
|
||||||
(.*/)*libXcursor.so.[0-9]+
|
|
||||||
(.*/)*libXdamage.so.[0-9]+
|
|
||||||
(.*/)*libXdmcp.so.[0-9]+
|
|
||||||
(.*/)*libXext.so.[0-9]+
|
|
||||||
(.*/)*libXfixes.so.[0-9]+
|
|
||||||
(.*/)*libXi.so.[0-9]+
|
|
||||||
(.*/)*libXinerama.so.[0-9]+
|
|
||||||
(.*/)*libXrandr.so.[0-9]+
|
|
||||||
(.*/)*libXrender.so.[0-9]+
|
|
||||||
(.*/)*libXss.so.[0-9]+
|
|
||||||
(.*/)*libXv.so.[0-9]+
|
|
||||||
(.*/)*libXxf86vm.so.[0-9]+
|
|
||||||
(.*/)*libglapi.so.[0-9]+
|
|
||||||
(.*/)*libp11-kit.so.[0-9]+
|
|
||||||
(.*/)*libxcb-dri2.so.[0-9]+
|
|
||||||
(.*/)*libxcb-dri3.so.[0-9]+
|
|
||||||
(.*/)*libxcb-glx.so.[0-9]+
|
|
||||||
(.*/)*libxcb-icccm.so.[0-9]+
|
|
||||||
(.*/)*libxcb-image.so.[0-9]+
|
|
||||||
(.*/)*libxcb-keysyms.so.[0-9]+
|
|
||||||
(.*/)*libxcb-present.so.[0-9]+
|
|
||||||
(.*/)*libxcb-randr.so.[0-9]+
|
|
||||||
(.*/)*libxcb-render-util.so.[0-9]+
|
|
||||||
(.*/)*libxcb-render.so.[0-9]+
|
|
||||||
(.*/)*libxcb-shape.so.[0-9]+
|
|
||||||
(.*/)*libxcb-shm.so.[0-9]+
|
|
||||||
(.*/)*libxcb-sync.so.[0-9]+
|
|
||||||
(.*/)*libxcb-util.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xfixes.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xinerama.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xkb.so.[0-9]+
|
|
||||||
(.*/)*libxcb.so.[0-9]+
|
|
||||||
(.*/)*libxkbcommon-x11.so.[0-9]+
|
|
||||||
(.*/)*libxkbcommon.so.[0-9]+
|
|
||||||
(.*/)*libxshmfence.so.[0-9]+
|
|
||||||
|
|
||||||
# OpenGL
|
|
||||||
(.*/)*libdrm.so.2
|
|
||||||
(.*/)*libgbm.so.1
|
|
||||||
(.*/)*libEGL.so.1
|
|
||||||
(.*/)*libGL.so.1
|
|
||||||
(.*/)*libGLX.so.0
|
|
||||||
(.*/)*libGLdispatch.so.0
|
|
||||||
|
|
||||||
# Use system library instead
|
|
||||||
(.*/)*libasound.so.2
|
|
||||||
(.*/)*libpulse.so.0
|
|
||||||
(.*/)*libpulse-simple.so.0
|
|
||||||
(.*/)*libjack.so.0
|
|
||||||
(.*/)*libv4l2.so.0
|
|
|
@ -1,110 +0,0 @@
|
||||||
# VDSO
|
|
||||||
(.*/)*ld-linux.so.2
|
|
||||||
(.*/)*ld-linux-x86-64.so.2
|
|
||||||
|
|
||||||
# Glibc
|
|
||||||
(.*/)*libc.so.[0-9]+
|
|
||||||
(.*/)*libdl.so.[0-9]+
|
|
||||||
(.*/)*libm.so.[0-9]+
|
|
||||||
(.*/)*libmvec.so.[0-9]+
|
|
||||||
(.*/)*libpthread.so.[0-9]+
|
|
||||||
(.*/)*libresolv.so.[0-9]+
|
|
||||||
(.*/)*librt.so.[0-9]+
|
|
||||||
|
|
||||||
# GCC
|
|
||||||
(.*/)*libgcc_s.so.[0-9]+
|
|
||||||
(.*/)*libgomp.so.[0-9]+
|
|
||||||
(.*/)*libstdc\+\+.so.[0-9]+
|
|
||||||
|
|
||||||
# Core libraries
|
|
||||||
(.*/)*libSM.so.6
|
|
||||||
(.*/)*libblkid.so.1
|
|
||||||
(.*/)*libcap.so.2
|
|
||||||
(.*/)*libcom_err.so.2
|
|
||||||
(.*/)*libcrypto.so.1.0.0
|
|
||||||
(.*/)*libdb-5.3.so
|
|
||||||
(.*/)*libdbus-1.so.3
|
|
||||||
(.*/)*libexpat.so.1
|
|
||||||
(.*/)*libfontconfig.so.1
|
|
||||||
(.*/)*libfreetype.so.6
|
|
||||||
(.*/)*libgcrypt.so.20
|
|
||||||
(.*/)*libgmp.so.10
|
|
||||||
(.*/)*libgpg-error.so.0
|
|
||||||
(.*/)*libgssapi_krb5.so.2
|
|
||||||
(.*/)*libharfbuzz.so.0
|
|
||||||
(.*/)*libk5crypto.so.3
|
|
||||||
(.*/)*libkeyutils.so.1
|
|
||||||
(.*/)*libkrb5.so.3
|
|
||||||
(.*/)*libkrb5support.so.0
|
|
||||||
(.*/)*liblz4.so.1
|
|
||||||
(.*/)*liblzma.so.5
|
|
||||||
(.*/)*libmount.so.1
|
|
||||||
(.*/)*libpcre.so.[0-9]+$
|
|
||||||
(.*/)*libpcre16.so.0
|
|
||||||
(.*/)*libssh2.so.1
|
|
||||||
(.*/)*libssl.so.1.0.0
|
|
||||||
(.*/)*libtasn1.so.6
|
|
||||||
(.*/)*libusb-1.0.so.0
|
|
||||||
(.*/)*libuuid.so.1
|
|
||||||
(.*/)*libz.so.1
|
|
||||||
|
|
||||||
# Glib2
|
|
||||||
(.*/)*libgio-2.0.so.0
|
|
||||||
(.*/)*libglib-2.0.so.0
|
|
||||||
(.*/)*libgmodule-2.0.so.0
|
|
||||||
(.*/)*libgobject-2.0.so.0
|
|
||||||
|
|
||||||
# X11
|
|
||||||
(.*/)*libX11-xcb.so.[0-9]+
|
|
||||||
(.*/)*libX11.so.[0-9]+
|
|
||||||
(.*/)*libXau.so.[0-9]+
|
|
||||||
(.*/)*libXcursor.so.[0-9]+
|
|
||||||
(.*/)*libXdamage.so.[0-9]+
|
|
||||||
(.*/)*libXdmcp.so.[0-9]+
|
|
||||||
(.*/)*libXext.so.[0-9]+
|
|
||||||
(.*/)*libXfixes.so.[0-9]+
|
|
||||||
(.*/)*libXi.so.[0-9]+
|
|
||||||
(.*/)*libXinerama.so.[0-9]+
|
|
||||||
(.*/)*libXrandr.so.[0-9]+
|
|
||||||
(.*/)*libXrender.so.[0-9]+
|
|
||||||
(.*/)*libXss.so.[0-9]+
|
|
||||||
(.*/)*libXv.so.[0-9]+
|
|
||||||
(.*/)*libXxf86vm.so.[0-9]+
|
|
||||||
(.*/)*libglapi.so.[0-9]+
|
|
||||||
(.*/)*libp11-kit.so.[0-9]+
|
|
||||||
(.*/)*libxcb-dri2.so.[0-9]+
|
|
||||||
(.*/)*libxcb-dri3.so.[0-9]+
|
|
||||||
(.*/)*libxcb-glx.so.[0-9]+
|
|
||||||
(.*/)*libxcb-icccm.so.[0-9]+
|
|
||||||
(.*/)*libxcb-image.so.[0-9]+
|
|
||||||
(.*/)*libxcb-keysyms.so.[0-9]+
|
|
||||||
(.*/)*libxcb-present.so.[0-9]+
|
|
||||||
(.*/)*libxcb-randr.so.[0-9]+
|
|
||||||
(.*/)*libxcb-render-util.so.[0-9]+
|
|
||||||
(.*/)*libxcb-render.so.[0-9]+
|
|
||||||
(.*/)*libxcb-shape.so.[0-9]+
|
|
||||||
(.*/)*libxcb-shm.so.[0-9]+
|
|
||||||
(.*/)*libxcb-sync.so.[0-9]+
|
|
||||||
(.*/)*libxcb-util.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xfixes.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xinerama.so.[0-9]+
|
|
||||||
(.*/)*libxcb-xkb.so.[0-9]+
|
|
||||||
(.*/)*libxcb.so.[0-9]+
|
|
||||||
(.*/)*libxkbcommon-x11.so.[0-9]+
|
|
||||||
(.*/)*libxkbcommon.so.[0-9]+
|
|
||||||
(.*/)*libxshmfence.so.[0-9]+
|
|
||||||
|
|
||||||
# OpenGL
|
|
||||||
(.*/)*libdrm.so.2
|
|
||||||
(.*/)*libgbm.so.1
|
|
||||||
(.*/)*libEGL.so.1
|
|
||||||
(.*/)*libGL.so.1
|
|
||||||
(.*/)*libGLX.so.0
|
|
||||||
(.*/)*libGLdispatch.so.0
|
|
||||||
|
|
||||||
# Use system library instead
|
|
||||||
(.*/)*libasound.so.2
|
|
||||||
(.*/)*libpulse.so.0
|
|
||||||
(.*/)*libpulse-simple.so.0
|
|
||||||
(.*/)*libjack.so.0
|
|
||||||
(.*/)*libv4l2.so.0
|
|
|
@ -1,691 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import configparser
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import subprocess # nosec
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
import tools.utils
|
|
||||||
|
|
||||||
|
|
||||||
class DeployToolsQt(tools.utils.DeployToolsUtils):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.qmake = ''
|
|
||||||
self.qtIFW = ''
|
|
||||||
self.qtIFWVersion = ''
|
|
||||||
self.qtInstallBins = ''
|
|
||||||
self.qtInstallQml = ''
|
|
||||||
self.qtInstallPlugins = ''
|
|
||||||
self.qmlRootDirs = []
|
|
||||||
self.qmlInstallDir = ''
|
|
||||||
self.dependencies = []
|
|
||||||
self.binarySolver = None
|
|
||||||
self.installerConfig = ''
|
|
||||||
self.appIcon = ''
|
|
||||||
self.installerRunProgram = ''
|
|
||||||
self.adminRights = False
|
|
||||||
|
|
||||||
def detectQt(self, path=''):
|
|
||||||
self.detectQmake(path)
|
|
||||||
self.qtInstallBins = self.qmakeQuery(var='QT_INSTALL_BINS')
|
|
||||||
self.qtInstallQml = self.qmakeQuery(var='QT_INSTALL_QML')
|
|
||||||
self.qtInstallPlugins = self.qmakeQuery(var='QT_INSTALL_PLUGINS')
|
|
||||||
self.detectQtIFW()
|
|
||||||
self.detectQtIFWVersion()
|
|
||||||
|
|
||||||
def detectQmake(self, path=''):
|
|
||||||
for makeFile in self.detectMakeFiles(path):
|
|
||||||
with open(makeFile) as f:
|
|
||||||
for line in f:
|
|
||||||
if line.startswith('QMAKE') and '=' in line:
|
|
||||||
self.qmake = line.split('=')[1].strip()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
if 'QMAKE_PATH' in os.environ:
|
|
||||||
self.qmake = os.environ['QMAKE_PATH']
|
|
||||||
|
|
||||||
def detectTargetBinaryFromQt5Make(self, path=''):
|
|
||||||
for makeFile in self.detectMakeFiles(path):
|
|
||||||
with open(makeFile) as f:
|
|
||||||
for line in f:
|
|
||||||
if line.startswith('TARGET') and '=' in line:
|
|
||||||
return os.path.join(path, line.split('=')[1].strip())
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def qmakeQuery(self, qmake='', var=''):
|
|
||||||
if qmake == '':
|
|
||||||
if 'QMAKE_PATH' in os.environ:
|
|
||||||
qmake = os.environ['QMAKE_PATH']
|
|
||||||
else:
|
|
||||||
qmake = self.qmake
|
|
||||||
|
|
||||||
try:
|
|
||||||
args = [qmake, '-query']
|
|
||||||
|
|
||||||
if var != '':
|
|
||||||
args += [var]
|
|
||||||
|
|
||||||
process = subprocess.Popen(args, # nosec
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
stdout, _ = process.communicate()
|
|
||||||
|
|
||||||
return stdout.strip().decode(sys.getdefaultencoding())
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def detectVersion(proFile):
|
|
||||||
if 'DAILY_BUILD' in os.environ:
|
|
||||||
return 'daily'
|
|
||||||
|
|
||||||
verMaj = '0'
|
|
||||||
verMin = '0'
|
|
||||||
verPat = '0'
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(proFile) as f:
|
|
||||||
for line in f:
|
|
||||||
if line.startswith('VER_MAJ') and '=' in line:
|
|
||||||
verMaj = line.split('=')[1].strip()
|
|
||||||
elif line.startswith('VER_MIN') and '=' in line:
|
|
||||||
verMin = line.split('=')[1].strip()
|
|
||||||
elif line.startswith('VER_PAT') and '=' in line:
|
|
||||||
verPat = line.split('=')[1].strip()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return verMaj + '.' + verMin + '.' + verPat
|
|
||||||
|
|
||||||
def detectQtIFW(self):
|
|
||||||
if 'BINARYCREATOR' in os.environ:
|
|
||||||
self.qtIFW = os.environ['BINARYCREATOR']
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
# Try official Qt binarycreator first because it is statically linked.
|
|
||||||
|
|
||||||
if self.targetSystem == 'windows':
|
|
||||||
homeQt = 'C:\\Qt'
|
|
||||||
elif self.targetSystem == 'posix_windows':
|
|
||||||
if 'WINEPREFIX' in os.environ:
|
|
||||||
homeQt = os.path.expanduser(os.path.join(os.environ['WINEPREFIX'],
|
|
||||||
'drive_c/Qt'))
|
|
||||||
else:
|
|
||||||
homeQt = os.path.expanduser('~/.wine/drive_c/Qt')
|
|
||||||
else:
|
|
||||||
homeQt = os.path.expanduser('~/Qt')
|
|
||||||
|
|
||||||
binCreator = 'binarycreator'
|
|
||||||
|
|
||||||
if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows':
|
|
||||||
binCreator += '.exe'
|
|
||||||
|
|
||||||
for root, _, files in os.walk(homeQt):
|
|
||||||
for f in files:
|
|
||||||
if f == binCreator:
|
|
||||||
self.qtIFW = os.path.join(root, f)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
# binarycreator offered by the system is most probably dynamically
|
|
||||||
# linked, so it's useful for test purposes only, but not recommended
|
|
||||||
# for distribution.
|
|
||||||
self.qtIFW = self.whereBin(binCreator)
|
|
||||||
|
|
||||||
def detectQtIFWVersion(self):
|
|
||||||
self.qtIFWVersion = ''
|
|
||||||
|
|
||||||
if self.qtIFW == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
installerBase = os.path.join(os.path.dirname(self.qtIFW),
|
|
||||||
'installerbase')
|
|
||||||
|
|
||||||
if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows':
|
|
||||||
installerBase += '.exe'
|
|
||||||
|
|
||||||
self.qtIFWVersion = '2.0.0'
|
|
||||||
|
|
||||||
if not os.path.exists(installerBase):
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.targetSystem == 'posix_windows':
|
|
||||||
installerBase = 'Z:' + installerBase.replace('/', '\\')
|
|
||||||
process = subprocess.Popen(['wine', # nosec
|
|
||||||
installerBase,
|
|
||||||
'--version'],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
stdout, _ = process.communicate(input=b'\n')
|
|
||||||
else:
|
|
||||||
process = subprocess.Popen([installerBase, # nosec
|
|
||||||
'--version'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
stdout, _ = process.communicate()
|
|
||||||
|
|
||||||
for line in stdout.split(b'\n'):
|
|
||||||
if b'IFW Version:' in line:
|
|
||||||
self.qtIFWVersion = line.split(b' ')[2].replace(b'"', b'').replace(b',', b'').decode(sys.getdefaultencoding())
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def listQmlFiles(path):
|
|
||||||
qmlFiles = set()
|
|
||||||
|
|
||||||
if os.path.isfile(path):
|
|
||||||
baseName = os.path.basename(path)
|
|
||||||
|
|
||||||
if baseName == 'qmldir' or path.endswith('.qml'):
|
|
||||||
qmlFiles.add(path)
|
|
||||||
else:
|
|
||||||
for root, _, files in os.walk(path):
|
|
||||||
for f in files:
|
|
||||||
if f == 'qmldir' or f.endswith('.qml'):
|
|
||||||
qmlFiles.add(os.path.join(root, f))
|
|
||||||
|
|
||||||
return list(qmlFiles)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def modulePath(importLine):
|
|
||||||
imp = importLine.strip().split()
|
|
||||||
path = imp[1].replace('.', '/')
|
|
||||||
majorVersion = imp[2].split('.')[0]
|
|
||||||
|
|
||||||
if int(majorVersion) > 1:
|
|
||||||
path += '.{}'.format(majorVersion)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
def scanImports(self, path):
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
return []
|
|
||||||
|
|
||||||
fileName = os.path.basename(path)
|
|
||||||
imports = set()
|
|
||||||
|
|
||||||
if fileName.endswith('.qml'):
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
for line in f:
|
|
||||||
if re.match(b'^import \\w+' , line):
|
|
||||||
imports.add(self.modulePath(line.strip().decode(sys.getdefaultencoding())))
|
|
||||||
elif fileName == 'qmldir':
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
for line in f:
|
|
||||||
if re.match(b'^depends ' , line):
|
|
||||||
imports.add(self.modulePath(line.strip().decode(sys.getdefaultencoding())))
|
|
||||||
|
|
||||||
return list(imports)
|
|
||||||
|
|
||||||
def solvedepsQml(self):
|
|
||||||
qmlFiles = set()
|
|
||||||
|
|
||||||
for path in self.qmlRootDirs:
|
|
||||||
path = os.path.join(self.rootDir, path)
|
|
||||||
|
|
||||||
for f in self.listQmlFiles(path):
|
|
||||||
qmlFiles.add(f)
|
|
||||||
|
|
||||||
solved = set()
|
|
||||||
solvedImports = set()
|
|
||||||
|
|
||||||
while len(qmlFiles) > 0:
|
|
||||||
qmlFile = qmlFiles.pop()
|
|
||||||
|
|
||||||
for imp in self.scanImports(qmlFile):
|
|
||||||
if imp in solvedImports:
|
|
||||||
continue
|
|
||||||
|
|
||||||
sysModulePath = os.path.join(self.qtInstallQml, imp)
|
|
||||||
installModulePath = os.path.join(self.qmlInstallDir, imp)
|
|
||||||
|
|
||||||
if os.path.exists(sysModulePath):
|
|
||||||
print(' {} -> {}'.format(sysModulePath, installModulePath))
|
|
||||||
self.copy(sysModulePath, installModulePath)
|
|
||||||
solvedImports.add(imp)
|
|
||||||
self.dependencies.append(os.path.join(sysModulePath, 'qmldir'))
|
|
||||||
|
|
||||||
for f in self.listQmlFiles(sysModulePath):
|
|
||||||
if not f in solved:
|
|
||||||
qmlFiles.add(f)
|
|
||||||
|
|
||||||
solved.add(qmlFile)
|
|
||||||
|
|
||||||
def solvedepsPlugins(self):
|
|
||||||
pluginsMap = {
|
|
||||||
'Qt53DRenderer': ['sceneparsers', 'geometryloaders'],
|
|
||||||
'Qt53DQuickRenderer': ['renderplugins'],
|
|
||||||
'Qt5Declarative': ['qml1tooling'],
|
|
||||||
'Qt5EglFSDeviceIntegration': ['egldeviceintegrations'],
|
|
||||||
'Qt5Gui': ['accessible',
|
|
||||||
'generic',
|
|
||||||
'iconengines',
|
|
||||||
'imageformats',
|
|
||||||
'platforms',
|
|
||||||
'platforminputcontexts',
|
|
||||||
'styles'],
|
|
||||||
'Qt5Location': ['geoservices'],
|
|
||||||
'Qt5Multimedia': ['audio', 'mediaservice', 'playlistformats'],
|
|
||||||
'Qt5Network': ['bearer'],
|
|
||||||
'Qt5Positioning': ['position'],
|
|
||||||
'Qt5PrintSupport': ['printsupport'],
|
|
||||||
'Qt5QmlTooling': ['qmltooling'],
|
|
||||||
'Qt5Quick': ['scenegraph', 'qmltooling'],
|
|
||||||
'Qt5Sensors': ['sensors', 'sensorgestures'],
|
|
||||||
'Qt5SerialBus': ['canbus'],
|
|
||||||
'Qt5Sql': ['sqldrivers'],
|
|
||||||
'Qt5TextToSpeech': ['texttospeech'],
|
|
||||||
'Qt5WebEngine': ['qtwebengine'],
|
|
||||||
'Qt5WebEngineCore': ['qtwebengine'],
|
|
||||||
'Qt5WebEngineWidgets': ['qtwebengine'],
|
|
||||||
'Qt5WebView': ['webview'],
|
|
||||||
'Qt5XcbQpa': ['xcbglintegrations']
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginsMap.update({lib + 'd': pluginsMap[lib] for lib in pluginsMap})
|
|
||||||
|
|
||||||
if self.targetSystem == 'android':
|
|
||||||
pluginsMap.update({lib + '_' + self.targetArch: pluginsMap[lib] for lib in pluginsMap})
|
|
||||||
|
|
||||||
plugins = []
|
|
||||||
|
|
||||||
for dep in self.binarySolver.scanDependencies(self.installDir):
|
|
||||||
libName = self.binarySolver.name(dep)
|
|
||||||
|
|
||||||
if not libName in pluginsMap:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for plugin in pluginsMap[libName]:
|
|
||||||
if not plugin in plugins:
|
|
||||||
sysPluginPath = os.path.join(self.qtInstallPlugins, plugin)
|
|
||||||
pluginPath = os.path.join(self.pluginsInstallDir, plugin)
|
|
||||||
|
|
||||||
if not os.path.exists(sysPluginPath):
|
|
||||||
continue
|
|
||||||
|
|
||||||
print(' {} -> {}'.format(sysPluginPath, pluginPath))
|
|
||||||
self.copy(sysPluginPath, pluginPath)
|
|
||||||
plugins.append(plugin)
|
|
||||||
self.dependencies.append(sysPluginPath)
|
|
||||||
|
|
||||||
def solvedepsAndroid(self):
|
|
||||||
installPrefix = self.qmakeQuery(var='QT_INSTALL_PREFIX')
|
|
||||||
qtLibsPath = self.qmakeQuery(var='QT_INSTALL_LIBS')
|
|
||||||
jars = []
|
|
||||||
permissions = set()
|
|
||||||
features = set()
|
|
||||||
initClasses = set()
|
|
||||||
libs = set()
|
|
||||||
|
|
||||||
for f in os.listdir(self.libInstallDir):
|
|
||||||
basename = os.path.basename(f)[3:]
|
|
||||||
basename = os.path.splitext(basename)[0]
|
|
||||||
depFile = os.path.join(qtLibsPath,
|
|
||||||
basename + '-android-dependencies.xml')
|
|
||||||
|
|
||||||
if os.path.exists(depFile):
|
|
||||||
tree = ET.parse(depFile)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
for jar in root.iter('jar'):
|
|
||||||
jars.append(jar.attrib['file'])
|
|
||||||
|
|
||||||
if 'initClass' in jar.attrib:
|
|
||||||
initClasses.append(jar.attrib['initClass'])
|
|
||||||
|
|
||||||
for permission in root.iter('permission'):
|
|
||||||
permissions.add(permission.attrib['name'])
|
|
||||||
|
|
||||||
for feature in root.iter('feature'):
|
|
||||||
features.add(feature.attrib['name'])
|
|
||||||
|
|
||||||
for lib in root.iter('lib'):
|
|
||||||
if 'file' in lib.attrib:
|
|
||||||
libs.add(lib.attrib['file'])
|
|
||||||
|
|
||||||
self.localLibs = [os.path.basename(lib) for lib in libs]
|
|
||||||
|
|
||||||
print('Copying jar files\n')
|
|
||||||
|
|
||||||
for jar in sorted(jars):
|
|
||||||
srcPath = os.path.join(installPrefix, jar)
|
|
||||||
dstPath = os.path.join(self.rootInstallDir,
|
|
||||||
'libs',
|
|
||||||
os.path.basename(jar))
|
|
||||||
print(' {} -> {}'.format(srcPath, dstPath))
|
|
||||||
self.copy(srcPath, dstPath)
|
|
||||||
|
|
||||||
manifest = os.path.join(self.rootInstallDir, 'AndroidManifest.xml')
|
|
||||||
manifestTemp = os.path.join(self.rootInstallDir, 'AndroidManifestTemp.xml')
|
|
||||||
tree = ET.parse(manifest)
|
|
||||||
root = tree.getroot()
|
|
||||||
oldFeatures = set()
|
|
||||||
oldPermissions = set()
|
|
||||||
|
|
||||||
for element in root:
|
|
||||||
if element.tag == 'uses-feature':
|
|
||||||
for key in element.attrib:
|
|
||||||
if key.endswith('name'):
|
|
||||||
oldFeatures.add(element.attrib[key])
|
|
||||||
elif element.tag == 'uses-permission':
|
|
||||||
for key in element.attrib:
|
|
||||||
if key.endswith('name'):
|
|
||||||
oldPermissions.add(element.attrib[key])
|
|
||||||
|
|
||||||
features -= oldFeatures
|
|
||||||
permissions -= oldPermissions
|
|
||||||
featuresWritten = len(features) < 1
|
|
||||||
permissionsWritten = len(permissions) < 1
|
|
||||||
replace = {'-- %%INSERT_INIT_CLASSES%% --' : ':'.join(sorted(initClasses)),
|
|
||||||
'-- %%BUNDLE_LOCAL_QT_LIBS%% --': '1',
|
|
||||||
'-- %%USE_LOCAL_QT_LIBS%% --' : '1',
|
|
||||||
'-- %%INSERT_LOCAL_LIBS%% --' : ':'.join(sorted(libs)),
|
|
||||||
'-- %%INSERT_LOCAL_JARS%% --' : ':'.join(sorted(jars))}
|
|
||||||
|
|
||||||
with open(manifest) as inFile:
|
|
||||||
with open(manifestTemp, 'w') as outFile:
|
|
||||||
for line in inFile:
|
|
||||||
for key in replace:
|
|
||||||
line = line.replace(key, replace[key])
|
|
||||||
|
|
||||||
outFile.write(line)
|
|
||||||
spaces = len(line)
|
|
||||||
line = line.lstrip()
|
|
||||||
spaces -= len(line)
|
|
||||||
|
|
||||||
if line.startswith('<uses-feature') and not featuresWritten:
|
|
||||||
print('\nUpdating features\n')
|
|
||||||
|
|
||||||
for feature in features:
|
|
||||||
print(' ' + feature)
|
|
||||||
outFile.write(spaces * ' ' + '<uses-feature android:name="{}"/>\n'.format(feature))
|
|
||||||
|
|
||||||
featuresWritten = True
|
|
||||||
|
|
||||||
if line.startswith('<uses-permission') and not permissionsWritten:
|
|
||||||
print('\nUpdating permissions\n')
|
|
||||||
|
|
||||||
for permission in permissions:
|
|
||||||
print(' ' + permission)
|
|
||||||
outFile.write(spaces * ' ' + '<uses-permission android:name="{}"/>\n'.format(permission))
|
|
||||||
|
|
||||||
permissionsWritten = True
|
|
||||||
|
|
||||||
os.remove(manifest)
|
|
||||||
shutil.move(manifestTemp, manifest)
|
|
||||||
|
|
||||||
def writeQtConf(self):
|
|
||||||
prefix = self.binaryInstallDir
|
|
||||||
|
|
||||||
if self.targetSystem == 'mac':
|
|
||||||
prefix = os.path.abspath(os.path.join(self.binaryInstallDir, '..'))
|
|
||||||
|
|
||||||
paths = {'Plugins': os.path.relpath(self.pluginsInstallDir, prefix).replace('\\', '/'),
|
|
||||||
'Imports': os.path.relpath(self.qmlInstallDir, prefix).replace('\\', '/'),
|
|
||||||
'Qml2Imports': os.path.relpath(self.qmlInstallDir, prefix).replace('\\', '/')}
|
|
||||||
confPath = os.path.dirname(self.qtConf)
|
|
||||||
|
|
||||||
if not os.path.exists(confPath):
|
|
||||||
os.makedirs(confPath)
|
|
||||||
|
|
||||||
with open(self.qtConf, 'w') as qtconf:
|
|
||||||
qtconf.write('[Paths]\n')
|
|
||||||
|
|
||||||
for path in paths:
|
|
||||||
qtconf.write('{} = {}\n'.format(path, paths[path]))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def readChangeLog(changeLog, appName, version):
|
|
||||||
if os.path.exists(changeLog):
|
|
||||||
with open(changeLog) as f:
|
|
||||||
for line in f:
|
|
||||||
if not line.startswith('{0} {1}:'.format(appName, version)):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Skip first line.
|
|
||||||
f.readline()
|
|
||||||
changeLogText = ''
|
|
||||||
|
|
||||||
for line_ in f:
|
|
||||||
if re.match('{} \d+\.\d+\.\d+:'.format(appName), line):
|
|
||||||
# Remove last line.
|
|
||||||
i = changeLogText.rfind('\n')
|
|
||||||
|
|
||||||
if i >= 0:
|
|
||||||
changeLogText = changeLogText[: i]
|
|
||||||
|
|
||||||
return changeLogText
|
|
||||||
|
|
||||||
changeLogText += line_
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def createInstaller(self):
|
|
||||||
if not os.path.exists(self.qtIFW):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Read package config
|
|
||||||
packageConf = configparser.ConfigParser()
|
|
||||||
packageConf.optionxform=str
|
|
||||||
packageConf.read(self.packageConfig, 'utf-8')
|
|
||||||
|
|
||||||
# Create layout
|
|
||||||
componentName = 'com.{0}prj.{0}'.format(self.programName)
|
|
||||||
packageDir = os.path.join(self.installerPackages, componentName)
|
|
||||||
|
|
||||||
if not os.path.exists(self.installerConfig):
|
|
||||||
os.makedirs(self.installerConfig)
|
|
||||||
|
|
||||||
dataDir = os.path.join(packageDir, 'data')
|
|
||||||
metaDir = os.path.join(packageDir, 'meta')
|
|
||||||
|
|
||||||
if not os.path.exists(dataDir):
|
|
||||||
os.makedirs(dataDir)
|
|
||||||
|
|
||||||
if not os.path.exists(metaDir):
|
|
||||||
os.makedirs(metaDir)
|
|
||||||
|
|
||||||
iconName = ''
|
|
||||||
|
|
||||||
if self.appIcon != '' and os.path.exists(self.appIcon):
|
|
||||||
self.copy(self.appIcon, self.installerConfig)
|
|
||||||
iconName = os.path.splitext(os.path.basename(self.appIcon))[0]
|
|
||||||
|
|
||||||
licenseOutFile = os.path.basename(self.licenseFile)
|
|
||||||
|
|
||||||
if not '.' in licenseOutFile and \
|
|
||||||
(self.targetSystem == 'windows' or \
|
|
||||||
self.targetSystem == 'posix_windows'):
|
|
||||||
licenseOutFile += '.txt'
|
|
||||||
|
|
||||||
self.copy(self.licenseFile, os.path.join(metaDir, licenseOutFile))
|
|
||||||
self.copy(self.rootInstallDir, dataDir)
|
|
||||||
|
|
||||||
configXml = os.path.join(self.installerConfig, 'config.xml')
|
|
||||||
appName = packageConf['Package']['appName'].strip()
|
|
||||||
|
|
||||||
with open(configXml, 'w') as config:
|
|
||||||
config.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
|
||||||
config.write('<Installer>\n')
|
|
||||||
config.write(' <Name>{}</Name>\n'.format(appName))
|
|
||||||
|
|
||||||
if 'DAILY_BUILD' in os.environ:
|
|
||||||
config.write(' <Version>0.0.0</Version>\n')
|
|
||||||
else:
|
|
||||||
config.write(' <Version>{}</Version>\n'.format(self.programVersion))
|
|
||||||
|
|
||||||
config.write(' <Title>{}</Title>\n'.format(packageConf['Package']['description'].strip()))
|
|
||||||
config.write(' <Publisher>{}</Publisher>\n'.format(appName))
|
|
||||||
config.write(' <ProductUrl>{}</ProductUrl>\n'.format(packageConf['Package']['url'].strip()))
|
|
||||||
|
|
||||||
if iconName != '':
|
|
||||||
config.write(' <InstallerWindowIcon>{}</InstallerWindowIcon>\n'.format(iconName))
|
|
||||||
config.write(' <InstallerApplicationIcon>{}</InstallerApplicationIcon>\n'.format(iconName))
|
|
||||||
config.write(' <Logo>{}</Logo>\n'.format(iconName))
|
|
||||||
|
|
||||||
if self.installerRunProgram != '':
|
|
||||||
config.write(' <RunProgram>{}</RunProgram>\n'.format(self.installerRunProgram))
|
|
||||||
config.write(' <RunProgramDescription>{}</RunProgramDescription>\n'.format(packageConf['Package']['runMessage'].strip()))
|
|
||||||
config.write(' <StartMenuDir>{}</StartMenuDir>\n'.format(appName))
|
|
||||||
|
|
||||||
config.write(' <MaintenanceToolName>{}Uninstall</MaintenanceToolName>\n'.format(appName))
|
|
||||||
config.write(' <AllowNonAsciiCharacters>true</AllowNonAsciiCharacters>\n')
|
|
||||||
config.write(' <TargetDir>{}</TargetDir>\n'.format(self.installerTargetDir))
|
|
||||||
config.write('</Installer>\n')
|
|
||||||
|
|
||||||
self.copy(self.installerScript,
|
|
||||||
os.path.join(metaDir, 'installscript.qs'))
|
|
||||||
|
|
||||||
with open(os.path.join(metaDir, 'package.xml'), 'w') as f:
|
|
||||||
f.write('<?xml version="1.0"?>\n')
|
|
||||||
f.write('<Package>\n')
|
|
||||||
f.write(' <DisplayName>{}</DisplayName>\n'.format(appName))
|
|
||||||
f.write(' <Description>{}</Description>\n'.format(packageConf['Package']['description'].strip()))
|
|
||||||
|
|
||||||
if 'DAILY_BUILD' in os.environ:
|
|
||||||
f.write(' <Version>0.0.0</Version>\n')
|
|
||||||
else:
|
|
||||||
f.write(' <Version>{}</Version>\n'.format(self.programVersion))
|
|
||||||
|
|
||||||
f.write(' <ReleaseDate>{}</ReleaseDate>\n'.format(time.strftime('%Y-%m-%d')))
|
|
||||||
f.write(' <Name>{}</Name>\n'.format(componentName))
|
|
||||||
f.write(' <Licenses>\n')
|
|
||||||
f.write(' <License name="{0}" file="{1}" />\n'.format(packageConf['Package']['licenseDescription'].strip(),
|
|
||||||
licenseOutFile))
|
|
||||||
f.write(' </Licenses>\n')
|
|
||||||
f.write(' <Script>installscript.qs</Script>\n')
|
|
||||||
f.write(' <UpdateText>\n')
|
|
||||||
|
|
||||||
if not 'DAILY_BUILD' in os.environ:
|
|
||||||
f.write(self.readChangeLog(self.changeLog,
|
|
||||||
appName,
|
|
||||||
self.programVersion))
|
|
||||||
|
|
||||||
f.write(' </UpdateText>\n')
|
|
||||||
f.write(' <Default>true</Default>\n')
|
|
||||||
f.write(' <ForcedInstallation>true</ForcedInstallation>\n')
|
|
||||||
f.write(' <Essential>false</Essential>\n')
|
|
||||||
|
|
||||||
if self.adminRights:
|
|
||||||
f.write(' <RequiresAdminRights>true</RequiresAdminRights>\n')
|
|
||||||
|
|
||||||
f.write('</Package>\n')
|
|
||||||
|
|
||||||
# Remove old file
|
|
||||||
if not os.path.exists(self.pkgsDir):
|
|
||||||
os.makedirs(self.pkgsDir)
|
|
||||||
|
|
||||||
if os.path.exists(self.outPackage):
|
|
||||||
os.remove(self.outPackage)
|
|
||||||
|
|
||||||
params = []
|
|
||||||
|
|
||||||
if self.targetSystem == 'posix_windows':
|
|
||||||
params = ['wine']
|
|
||||||
|
|
||||||
params += [self.qtIFW,
|
|
||||||
'-c', configXml,
|
|
||||||
'-p', self.installerPackages,
|
|
||||||
self.outPackage]
|
|
||||||
process = subprocess.Popen(params, # nosec
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def copyAndroidTemplates(self):
|
|
||||||
installPrefix = self.qmakeQuery(var='QT_INSTALL_PREFIX')
|
|
||||||
sourcesPath = os.path.join(installPrefix, 'src')
|
|
||||||
templates = [os.path.join(sourcesPath, '3rdparty/gradle'),
|
|
||||||
os.path.join(sourcesPath, 'android/templates')]
|
|
||||||
|
|
||||||
for template in templates:
|
|
||||||
self.copy(template, self.rootInstallDir, overwrite=False)
|
|
||||||
|
|
||||||
deploymentSettingsPath = ''
|
|
||||||
|
|
||||||
for f in os.listdir(self.standAloneDir):
|
|
||||||
if re.match('^android-.+-deployment-settings.json$' , f):
|
|
||||||
deploymentSettingsPath = os.path.join(self.standAloneDir, f)
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
if len(deploymentSettingsPath) < 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
with open(deploymentSettingsPath) as f:
|
|
||||||
deploymentSettings = json.load(f)
|
|
||||||
|
|
||||||
properties = os.path.join(self.rootInstallDir, 'gradle.properties')
|
|
||||||
platform = self.androidPlatform.replace('android-', '')
|
|
||||||
javaDir = os.path.join(sourcesPath, 'android','java')
|
|
||||||
|
|
||||||
with open(properties, 'w') as f:
|
|
||||||
if 'sdkBuildToolsRevision' in deploymentSettings:
|
|
||||||
f.write('androidBuildToolsVersion={}\n'.format(deploymentSettings['sdkBuildToolsRevision']))
|
|
||||||
|
|
||||||
f.write('androidCompileSdkVersion={}\n'.format(platform))
|
|
||||||
f.write('buildDir=build\n')
|
|
||||||
f.write('qt5AndroidDir={}\n'.format(javaDir))
|
|
||||||
|
|
||||||
def createRccBundle(self):
|
|
||||||
rcc = os.path.join(os.path.dirname(self.qmake), 'rcc')
|
|
||||||
assetsDir = os.path.abspath(os.path.join(self.assetsIntallDir, '..'))
|
|
||||||
assetsFolder = os.path.relpath(self.assetsIntallDir, assetsDir)
|
|
||||||
qrcFile = os.path.join(self.assetsIntallDir, assetsFolder + '.qrc')
|
|
||||||
|
|
||||||
params = [rcc,
|
|
||||||
'--project',
|
|
||||||
'-o', qrcFile]
|
|
||||||
process = subprocess.Popen(params, # nosec
|
|
||||||
cwd=self.assetsIntallDir,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
params = [rcc,
|
|
||||||
'--root=/{}'.format(assetsFolder),
|
|
||||||
'--binary',
|
|
||||||
'-o', self.assetsIntallDir + '.rcc',
|
|
||||||
qrcFile]
|
|
||||||
process = subprocess.Popen(params, # nosec
|
|
||||||
cwd=assetsDir,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process.communicate()
|
|
||||||
|
|
||||||
shutil.rmtree(self.assetsIntallDir, True)
|
|
|
@ -1,255 +0,0 @@
|
||||||
#!/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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Web-Site: http://webcamoid.github.io/
|
|
||||||
|
|
||||||
import fnmatch
|
|
||||||
import hashlib
|
|
||||||
import multiprocessing
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
import subprocess # nosec
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class DeployToolsUtils:
|
|
||||||
def __init__(self):
|
|
||||||
self.make = ''
|
|
||||||
|
|
||||||
if os.name == 'posix' and sys.platform.startswith('darwin'):
|
|
||||||
self.system = 'mac'
|
|
||||||
elif os.name == 'nt' and sys.platform.startswith('win32'):
|
|
||||||
self.system = 'windows'
|
|
||||||
elif os.name == 'posix':
|
|
||||||
self.system = 'posix'
|
|
||||||
else:
|
|
||||||
self.system = ''
|
|
||||||
|
|
||||||
self.arch = platform.architecture()[0]
|
|
||||||
self.targetArch = self.arch
|
|
||||||
self.targetSystem = self.system
|
|
||||||
pathSep = ';' if self.system == 'windows' else ':'
|
|
||||||
self.sysBinsPath = []
|
|
||||||
|
|
||||||
if 'PATH' in os.environ:
|
|
||||||
self.sysBinsPath += \
|
|
||||||
[path.strip() for path in os.environ['PATH'].split(pathSep)]
|
|
||||||
|
|
||||||
self.njobs = multiprocessing.cpu_count()
|
|
||||||
|
|
||||||
if self.njobs < 4:
|
|
||||||
self.njobs = 4
|
|
||||||
|
|
||||||
def detectTargetArch(self, binary=''):
|
|
||||||
if binary == '':
|
|
||||||
binary = self.mainBinary
|
|
||||||
|
|
||||||
self.targetArch = platform.architecture(binary)[0]
|
|
||||||
|
|
||||||
def whereBin(self, binary):
|
|
||||||
for path in self.sysBinsPath:
|
|
||||||
path = os.path.join(path, binary)
|
|
||||||
|
|
||||||
if os.path.exists(path):
|
|
||||||
return path
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def copy(self, src, dst='.', copyReals=False, overwrite=True):
|
|
||||||
if not os.path.exists(src):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if os.path.isdir(src):
|
|
||||||
if os.path.isfile(dst):
|
|
||||||
return False
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(src):
|
|
||||||
for f in files:
|
|
||||||
fromF = os.path.join(root, f)
|
|
||||||
toF = os.path.relpath(fromF, src)
|
|
||||||
toF = os.path.join(dst, toF)
|
|
||||||
toF = os.path.normpath(toF)
|
|
||||||
self.copy(fromF, toF, copyReals, overwrite)
|
|
||||||
|
|
||||||
for d in dirs:
|
|
||||||
fromD = os.path.join(root, d)
|
|
||||||
toD = os.path.relpath(fromD, src)
|
|
||||||
toD = os.path.join(dst, toD)
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.normpath(toD))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
elif os.path.isfile(src):
|
|
||||||
if os.path.isdir(dst):
|
|
||||||
dst = os.path.realpath(dst)
|
|
||||||
dst = os.path.join(dst, os.path.basename(src))
|
|
||||||
|
|
||||||
dirname = os.path.dirname(dst)
|
|
||||||
|
|
||||||
if not os.path.exists(dirname):
|
|
||||||
try:
|
|
||||||
os.makedirs(dirname)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if os.path.exists(dst):
|
|
||||||
if not overwrite:
|
|
||||||
return True
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.remove(dst)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if copyReals and os.path.islink(src):
|
|
||||||
realpath = os.path.realpath(src)
|
|
||||||
basename = os.path.basename(realpath)
|
|
||||||
os.symlink(os.path.join('.', basename), dst)
|
|
||||||
self.copy(realpath,
|
|
||||||
os.path.join(dirname, basename),
|
|
||||||
copyReals,
|
|
||||||
overwrite)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if self.system == 'windows':
|
|
||||||
shutil.copy(src, dst)
|
|
||||||
else:
|
|
||||||
shutil.copy(src, dst, follow_symlinks=False)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def move(self, src, dst='.', moveReals=False):
|
|
||||||
if not os.path.exists(src):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if os.path.isdir(src):
|
|
||||||
if os.path.isfile(dst):
|
|
||||||
return False
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(src):
|
|
||||||
for f in files:
|
|
||||||
fromF = os.path.join(root, f)
|
|
||||||
toF = os.path.relpath(fromF, src)
|
|
||||||
toF = os.path.join(dst, toF)
|
|
||||||
toF = os.path.normpath(toF)
|
|
||||||
self.move(fromF, toF, moveReals)
|
|
||||||
|
|
||||||
for d in dirs:
|
|
||||||
fromD = os.path.join(root, d)
|
|
||||||
toD = os.path.relpath(fromD, src)
|
|
||||||
toD = os.path.join(dst, toD)
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.normpath(toD))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
elif os.path.isfile(src):
|
|
||||||
if os.path.isdir(dst):
|
|
||||||
dst = os.path.realpath(dst)
|
|
||||||
dst = os.path.join(dst, os.path.basename(src))
|
|
||||||
|
|
||||||
dirname = os.path.dirname(dst)
|
|
||||||
|
|
||||||
if not os.path.exists(dirname):
|
|
||||||
try:
|
|
||||||
os.makedirs(dirname)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if os.path.exists(dst):
|
|
||||||
try:
|
|
||||||
os.remove(dst)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if moveReals and os.path.islink(src):
|
|
||||||
realpath = os.path.realpath(src)
|
|
||||||
basename = os.path.basename(realpath)
|
|
||||||
os.symlink(os.path.join('.', basename), dst)
|
|
||||||
self.move(realpath, os.path.join(dirname, basename), moveReals)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
shutil.move(src, dst)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def detectMake(self):
|
|
||||||
if 'MAKE_PATH' in os.environ:
|
|
||||||
self.make = os.environ['MAKE_PATH']
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
makes = ['mingw32-make', 'make'] if self.system == 'windows' else ['make']
|
|
||||||
ext = '.exe' if self.system == 'windows' else ''
|
|
||||||
|
|
||||||
for make in makes:
|
|
||||||
makePath = self.whereBin(make + ext)
|
|
||||||
|
|
||||||
if makePath != '':
|
|
||||||
self.make = makePath
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
def makeInstall(self, buildDir, params={}):
|
|
||||||
previousDir = os.getcwd()
|
|
||||||
os.chdir(buildDir)
|
|
||||||
params_ = [key + '=' + params[key] for key in params]
|
|
||||||
process = subprocess.Popen([self.make, 'install'] + params_, # nosec
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
|
|
||||||
process.communicate()
|
|
||||||
os.chdir(previousDir)
|
|
||||||
|
|
||||||
return process.returncode
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def sha256sum(fileName):
|
|
||||||
sha = hashlib.sha256()
|
|
||||||
|
|
||||||
with open(fileName, 'rb') as f:
|
|
||||||
while True:
|
|
||||||
data = f.read(1024)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
|
|
||||||
sha.update(data)
|
|
||||||
|
|
||||||
return sha.hexdigest()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def detectMakeFiles(makePath):
|
|
||||||
makeFiles = []
|
|
||||||
|
|
||||||
try:
|
|
||||||
for f in os.listdir(makePath):
|
|
||||||
path = os.path.join(makePath, f)
|
|
||||||
|
|
||||||
if os.path.isfile(path) and fnmatch.fnmatch(f.lower(), 'makefile*'):
|
|
||||||
makeFiles += [path]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return makeFiles
|
|
Loading…
Reference in a new issue