Using WebcamoidDeployTools.

This commit is contained in:
Gonzalo Exequiel Pedone 2020-11-18 16:33:36 -03:00
parent e5097d3911
commit 14265e1220
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
19 changed files with 44 additions and 2382 deletions

View file

@ -18,5 +18,10 @@
#
# Web-Site: http://webcamoid.github.io/
cd ports/deploy
git clone https://github.com/webcamoid/DeployTools.git
cd ../..
export PATH=/mingw64/bin:$PATH
export PYTHONPATH="${PWD}/ports/deploy/DeployTools"
python3 ports/deploy/deploy.py

View file

@ -22,6 +22,10 @@ if [ "${TRAVIS_OS_NAME}" = linux ]; then
EXEC='sudo ./root.x86_64/bin/arch-chroot root.x86_64'
fi
cd ports/deploy
git clone https://github.com/webcamoid/DeployTools.git
cd ../..
DEPLOYSCRIPT=deployscript.sh
if [ "${TRAVIS_OS_NAME}" = linux ]; then
@ -34,6 +38,7 @@ if [ "${TRAVIS_OS_NAME}" = linux ]; then
export LC_ALL=C
export HOME=$HOME
export PATH="$TRAVIS_BUILD_DIR/.local/bin:\$PATH"
export PYTHONPATH="\$PWD/ports/deploy/DeployTools"
export WINEPREFIX=/opt/.wine
cd $TRAVIS_BUILD_DIR
EOF

View file

@ -19,11 +19,11 @@
#
# Web-Site: http://webcamoid.github.io/
import tools.utils
from WebcamoidDeployTools import DTUtils
if __name__ =='__main__':
system = tools.utils.DeployToolsUtils().system
system = DTUtils.Utils().system
while True:
try:

View file

@ -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)

View file

@ -28,14 +28,16 @@ import sys
import threading
import time
import deploy_base
import tools.binary_mach
import tools.qt5
from WebcamoidDeployTools import DTDeployBase
from WebcamoidDeployTools import DTQt5
from WebcamoidDeployTools import DTBinaryMach
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
def __init__(self):
super().__init__()
rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
self.setRootDir(rootDir)
self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', self.targetSystem)
self.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.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri'))
self.detectMake()
self.binarySolver = tools.binary_mach.DeployToolsBinary()
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
self.binarySolver = DTBinaryMach.MachBinaryTools()
self.binarySolver.readExcludes(os.name, sys.platform)
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
self.dependencies = []
self.installerConfig = os.path.join(self.installDir, 'installer/config')

View file

@ -28,14 +28,16 @@ import sys
import tarfile
import threading
import deploy_base
import tools.binary_elf
import tools.qt5
from WebcamoidDeployTools import DTDeployBase
from WebcamoidDeployTools import DTQt5
from WebcamoidDeployTools import DTBinaryElf
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
def __init__(self):
super().__init__()
rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
self.setRootDir(rootDir)
self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', sys.platform)
self.detectQt(os.path.join(self.buildDir, 'Manager'))
@ -52,8 +54,8 @@ class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
elif 'android' in xspec:
self.targetSystem = 'android'
self.binarySolver = tools.binary_elf.DeployToolsBinary()
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
self.binarySolver = DTBinaryElf.ElfBinaryTools()
self.binarySolver.readExcludes(os.name, sys.platform)
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
self.dependencies = []
self.installerConfig = os.path.join(self.installDir, 'installer/config')

View file

@ -26,14 +26,16 @@ import sys
import threading
import zipfile
import deploy_base
import tools.binary_pecoff
import tools.qt5
from WebcamoidDeployTools import DTDeployBase
from WebcamoidDeployTools import DTQt5
from WebcamoidDeployTools import DTBinaryPecoff
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
def __init__(self):
super().__init__()
rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
self.setRootDir(rootDir)
self.targetSystem = 'posix_windows'
self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
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.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri'))
self.detectMake()
self.binarySolver = tools.binary_pecoff.DeployToolsBinary()
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
self.binarySolver = DTBinaryPecoff.PecoffBinaryTools()
self.binarySolver.readExcludes(os.name, sys.platform)
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
self.dependencies = []
self.installerConfig = os.path.join(self.installDir, 'installer/config')

View file

@ -27,14 +27,16 @@ import sys
import threading
import zipfile
import deploy_base
import tools.binary_pecoff
import tools.qt5
from WebcamoidDeployTools import DTDeployBase
from WebcamoidDeployTools import DTQt5
from WebcamoidDeployTools import DTBinaryPecoff
class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt):
class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools):
def __init__(self):
super().__init__()
rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..'))
self.setRootDir(rootDir)
self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv')
self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows')
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.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri'))
self.detectMake()
self.binarySolver = tools.binary_pecoff.DeployToolsBinary()
self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/tools/exclude/exclude.{}.{}.txt'.format(os.name, sys.platform)))
self.binarySolver = DTBinaryPecoff.PecoffBinaryTools()
self.binarySolver.readExcludes(os.name, sys.platform)
self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf')
self.dependencies = []
self.installerConfig = os.path.join(self.installDir, 'installer/config')

View file

@ -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)

View file

@ -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)

View file

@ -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'

View file

@ -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

View file

@ -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('.')]

View file

@ -1,2 +0,0 @@
C:/Windows/System32/.*
C:/Program Files/.*

View file

@ -1,2 +0,0 @@
/usr/lib/.*
/System/Library/Frameworks/.*

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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