Renovation

- rename package
- rename command utility
- use six for compatibility

Signed-off-by: Hiroshi Miura <miurahr@linux.com>
This commit is contained in:
Hiroshi Miura
2019-03-06 12:48:42 +09:00
parent f58f4a66bb
commit 2eecd94496
11 changed files with 305 additions and 215 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.venv
build
dist
venv

View File

@@ -17,7 +17,8 @@ Added
Changed Changed
------- -------
* Install not only basic packages also optional pacakges. * Install not only basic packages also optional packages.
* Rename project/command to aqt - Another QT installer
Fixed Fixed
----- -----
@@ -39,7 +40,7 @@ Security
Changed Changed
------- -------
* Support multiprocess concurent download and installation. * Support multiprocess concurrent download and installation.
`v0.0.2`_ (4, March, 2019) `v0.0.2`_ (4, March, 2019)
======================== ========================

View File

@@ -1,5 +1,5 @@
Qt CLI installer Another Qt installer(aqt)
################ =========================
.. |macos| image:: https://dev.azure.com/miurahr/github/_apis/build/status/miurahr.qli-installer?branchName=master&jobName=macOS .. |macos| image:: https://dev.azure.com/miurahr/github/_apis/build/status/miurahr.qli-installer?branchName=master&jobName=macOS
:target: https://dev.azure.com/miurahr/github/_build/latest?definitionId=6&branchName=master :target: https://dev.azure.com/miurahr/github/_build/latest?definitionId=6&branchName=master

68
aqt/__init__.py Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
#
# Copyright (C) 2018 Linus Jahn <lnj@kaidan.im>
# Copyright (C) 2019 Hiroshi Miura <miurahr@linux.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse
import sys
from argparse import RawTextHelpFormatter
from aqt.archives import QtArchives
from aqt.installer import QtInstaller
def main():
parser = argparse.ArgumentParser(description='Install Qt SDK.', formatter_class=RawTextHelpFormatter, add_help=True)
parser.add_argument("qt_version", help="Qt version in the format of \"5.X.Y\"")
parser.add_argument('host', choices=['linux', 'mac', 'windows'], help="host os name")
parser.add_argument('target', choices=['desktop', 'android', 'ios'], help="target sdk")
parser.add_argument('arch', nargs='?', help="\ntarget linux/desktop: gcc_64"
"\ntarget mac/desktop: clang_64"
"\ntarget mac/ios: ios"
"\nwindows/desktop: win64_msvc2017_64, win64_msvc2015_64"
"\n in32_msvc2015, win32_mingw53"
"\nandroid: android_x86, android_armv7")
args = parser.parse_args()
arch = args.arch
target = args.target
os_name = args.host
if arch is None:
if os_name == "linux" and target == "desktop":
arch = "gcc_64"
elif os_name == "mac" and target == "desktop":
arch = "clang_64"
elif os_name == "mac" and target == "ios":
arch = "ios"
if arch == "":
print("Please supply a target architecture.")
args.print_help()
exit(1)
qt_version = args.qt_version
archives = QtArchives(os_name, qt_version, target, arch)
qt_installer = QtInstaller(archives)
qt_installer.install(qt_version, arch)
sys.stdout.write("\033[K")
print("Finished installation")
if __name__ == "__main__":
sys.exit(main())

97
aqt/archives.py Normal file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python
#
# Copyright (C) 2018 Linus Jahn <lnj@kaidan.im>
# Copyright (C) 2019 Hiroshi Miura <miurahr@linux.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from six.moves import urllib
import xml.etree.ElementTree as ElementTree
class QtPackage:
name = ""
url = ""
archive = ""
desc = ""
def __init__(self, name, archive_url, archive, package_desc):
self.name = name
self.url = archive_url
self.archive = archive
self.desc = package_desc
def get_name(self):
return self.name
def get_url(self):
return self.url
def get_archive(self):
return self.archive
def get_desc(self):
return self.desc
class QtArchives:
BASE_URL = 'https://download.qt.io/online/qtsdkrepository/'
archives = []
def __init__(self, os_name, qt_version, target, arch):
qt_ver_num = qt_version.replace(".", "")
if os_name == 'windows':
archive_url = self.BASE_URL + os_name + '_x86/' + target + '/' + 'qt5_' + qt_ver_num + '/'
else:
archive_url = self.BASE_URL + os_name + '_x64/' + target + '/' + 'qt5_' + qt_ver_num + '/'
# Get packages index
update_xml_url = "{0}Updates.xml".format(archive_url)
proxies = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(proxies)
urllib.request.install_opener(opener)
content = urllib.request.urlopen(update_xml_url).read()
self.update_xml = ElementTree.fromstring(content)
for packageupdate in self.update_xml.iter("PackageUpdate"):
name = packageupdate.find("Name").text
if name.split(".")[-1] != arch:
continue
if name.split(".")[-2] == "debug_info":
continue
if packageupdate.find("DownloadableArchives").text is None:
continue
if name == "qt.qt5.{}.{}".format(qt_ver_num, arch) or name == "qt.{}.{}".format(qt_ver_num, arch):
# basic packages
pass
else:
# optional packages: FIXME: check option whether install or not
pass
downloadable_archives = packageupdate.find("DownloadableArchives").text.split(", ")
full_version = packageupdate.find("Version").text
package_desc = packageupdate.find("Description").text
for archive in downloadable_archives:
package_url = archive_url + name + "/" + full_version + archive
self.archives.append(QtPackage(name, package_url, archive, package_desc))
if len(self.archives) == 0:
print("Error while parsing package information!")
exit(1)
def get_archives(self):
return self.archives

93
aqt/installer.py Normal file
View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018 Linus Jahn <lnj@kaidan.im>
# Copyright (C) 2019 Hiroshi Miura <miurahr@linux.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import os
import platform
import subprocess
import sys
from six.moves import urllib
from multiprocessing.dummy import Pool
NUM_PROCESS = 3
class QtInstaller:
def __init__(self, qt_archives):
self.qt_archives = qt_archives
@staticmethod
def retrieve_archive(package):
archive = package.get_archive()
url = package.get_url()
sys.stdout.write("\033[K")
print("-Downloading {}...".format(url))
proxies = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(proxies)
urllib.request.install_opener(opener)
urllib.request.urlretrieve(url, archive)
sys.stdout.write("\033[K")
print("-Extracting {}...".format(archive))
if platform.system() is 'Windows':
subprocess.run([r'C:\Program Files\7-Zip\7z.exe', 'x', '-aoa', '-y', archive])
else:
subprocess.run([r'7z', 'x', '-aoa', '-y', archive])
os.unlink(archive)
@staticmethod
def get_base_dir(qt_version):
return os.path.join(os.getcwd(), 'Qt{}'.format(qt_version))
def install(self, qt_version, arch):
if arch.startswith('win'):
arch_dir = arch[6:]
else:
arch_dir = arch
base_dir = self.get_base_dir(qt_version)
if not os.path.exists(base_dir):
os.mkdir(base_dir)
elif not os.path.isdir(base_dir):
os.unlink(base_dir)
os.mkdir(base_dir)
os.chdir(base_dir)
p = Pool(NUM_PROCESS)
archives = self.qt_archives.get_archives()
p.map(self.retrieve_archive, archives)
try:
# prepare qt.conf
with open(os.path.join(base_dir, qt_version, arch_dir, 'bin', 'qt.conf'), 'w') as f:
f.write("[Paths]\n")
f.write("Prefix=..\n")
# prepare qtconfig.pri
with open(os.path.join(base_dir, qt_version, arch_dir, 'mkspecs', 'qconfig.pri'), 'r+') as f:
lines = f.readlines()
f.seek(0)
f.truncate()
for line in lines:
if 'QT_EDITION' in line:
line = 'QT_EDITION = OpenSource'
f.write(line)
except:
pass

4
qli-install → aqtinst Executable file → Normal file
View File

@@ -1,8 +1,8 @@
#!/bin/env python3 #!/usr/bin/env python3
import sys import sys
from qli-installer import main from aqt import main
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -11,13 +11,19 @@ jobs:
inputs: inputs:
versionSpec: '3.6' versionSpec: '3.6'
architecture: 'x64' architecture: 'x64'
- script: |
python -m pip install six flake8
flake8 .
displayName: 'Run lint tests'
os_name = args.host
target = args.target
- script: | - script: |
sudo apt-get update sudo apt-get update
sudo apt-get -y install p7zip-full sudo apt-get -y install p7zip-full
- task: PythonScript@0 - task: PythonScript@0
inputs: inputs:
scriptSource: filePath scriptSource: filePath
scriptPath: $(Build.SourcesDirectory)/qli-installer.py scriptPath: $(Build.SourcesDirectory)/aqtinst
arguments: $(qtversion) linux desktop arguments: $(qtversion) linux desktop
workingDirectory: $(Build.BinariesDirectory) workingDirectory: $(Build.BinariesDirectory)
displayName: install qt displayName: install qt
@@ -32,10 +38,12 @@ jobs:
versionSpec: '3.6' versionSpec: '3.6'
architecture: 'x64' architecture: 'x64'
- script: brew install p7zip - script: brew install p7zip
- script: pip install -r requirements.txt
displayName: 'Install requirements'
- task: PythonScript@0 - task: PythonScript@0
inputs: inputs:
scriptSource: filePath scriptSource: filePath
scriptPath: $(Build.SourcesDirectory)/qli-installer.py scriptPath: $(Build.SourcesDirectory)/aqtinst
arguments: $(qtversion) mac desktop arguments: $(qtversion) mac desktop
workingDirectory: $(Build.BinariesDirectory) workingDirectory: $(Build.BinariesDirectory)
displayName: install qt displayName: install qt
@@ -50,10 +58,12 @@ jobs:
versionSpec: '3.6' versionSpec: '3.6'
architecture: 'x64' architecture: 'x64'
- script: cinst -y 7zip - script: cinst -y 7zip
- script: pip install -r requirements.txt
displayName: 'Install requirements'
- task: PythonScript@0 - task: PythonScript@0
inputs: inputs:
scriptSource: filePath scriptSource: filePath
scriptPath: $(Build.SourcesDirectory)/qli-installer.py scriptPath: $(Build.SourcesDirectory)/aqtinst
arguments: $(qtversion) windows desktop win64_msvc2017_64 arguments: $(qtversion) windows desktop win64_msvc2017_64
workingDirectory: $(Build.BinariesDirectory) workingDirectory: $(Build.BinariesDirectory)
displayName: install qt displayName: install qt

View File

@@ -1,206 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018 Linus Jahn <lnj@kaidan.im>
# Copyright (C) 2019 Hiroshi Miura <miurahr@linux.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import argparse
import os
import platform
import subprocess
import sys
import urllib.request
import xml.etree.ElementTree as ElementTree
from argparse import RawTextHelpFormatter
from multiprocessing.dummy import Pool
BASE_URL = "https://download.qt.io/online/qtsdkrepository/"
NUM_PROCESS = 3
class QtPackage:
name = ""
url = ""
archive = ""
desc = ""
def __init__(self, name, archive_url, archive, package_desc):
self.name = name
self.url = archive_url
self.archive = archive
self.desc = package_desc
def get_name(self):
return self.name
def get_url(self):
return self.url
def get_archive(self):
return self.archive
def get_desc(self):
return self.desc
class QtArchives:
archives = []
def __init__(self, os_name, qt_version, target, arch):
qt_ver_num = qt_version.replace(".", "")
archive_url = BASE_URL
if os_name == "windows":
archive_url += os_name + "_x86/"
else:
archive_url += os_name + "_x64/"
archive_url += target + "/" + "qt5_" + qt_ver_num + "/"
# Get packages index
update_xml_url = archive_url + "Updates.xml"
content = urllib.request.urlopen(update_xml_url).read()
self.update_xml = ElementTree.fromstring(content)
for packageupdate in self.update_xml.iter("PackageUpdate"):
if packageupdate.find("DownloadableArchives").text is None:
continue
name = packageupdate.find("Name").text
downloadable_archives = packageupdate.find("DownloadableArchives").text.split(", ")
full_version = packageupdate.find("Version").text
package_desc = packageupdate.find("Description").text
for archive in downloadable_archives:
package_url = archive_url + name + "/" + full_version + archive
self.archives.append(QtPackage(name, package_url, archive, package_desc))
if len(self.archives)==0:
print("Error while parsing package information!")
exit(1)
def get_archives(self):
return self.archives
class QtInstaller:
def __init__(self, qt_archives):
self.qt_archives = qt_archives
def retrieve_archive(self, package):
archive = package.get_archive()
url = package.get_url()
sys.stdout.write("\033[K")
print("-Downloading {}...".format(url))
urllib.request.urlretrieve(url, archive)
sys.stdout.write("\033[K")
print("-Extracting {}...".format(archive))
if platform.system() is 'Windows':
subprocess.run([r'C:\Program Files\7-Zip\7z.exe', 'x', '-aoa', '-y', archive])
else:
subprocess.run([r'7z', 'x', '-aoa', '-y', archive])
os.unlink(archive)
def get_base_dir(self, qt_version):
return os.path.join(os.getcwd(), 'Qt{}'.format(qt_version))
def install(self, qt_version, arch):
if arch.startswith('win'):
arch_dir = arch[6:]
else:
arch_dir = arch
base_dir = self.get_base_dir(qt_version)
if not os.path.exists(base_dir):
os.mkdir(base_dir)
elif not os.path.isdir(base_dir):
os.unlink(base_dir)
os.mkdir(base_dir)
os.chdir(base_dir)
p = Pool(NUM_PROCESS)
archives = self.qt_archives.get_archives()
p.map(self.retrieve_archive, archives)
try:
# prepare qt.conf
with open(os.path.join(base_dir, qt_version, arch_dir, 'bin', 'qt.conf'), 'w') as f:
f.write("[Paths]\n")
f.write("Prefix=..\n")
# prepare qtconfig.pri
with open(os.path.join(base_dir, qt_version, arch_dir, 'mkspecs', 'qconfig.pri'), 'r+') as f:
lines = f.readlines()
f.seek(0)
f.truncate()
for line in lines:
if 'QT_EDITION' in line:
line = 'QT_EDITION = OpenSource'
f.write(line)
except:
pass
def show_help():
print("Usage: {} <qt-version> <host> <target> [<arch>]\n".format(sys.argv[0]))
print("qt-version: Qt version in the format of \"5.X.Y\"")
print("host systems: linux, mac, windows")
print("targets: desktop, android, ios")
print("arch: ")
print(" target linux/desktop: gcc_64")
print(" target mac/desktop: clang_64")
print(" target mac/ios: ios")
print(" windows/desktop: win64_msvc2017_64, win64_msvc2015_64")
print(" in32_msvc2015, win32_mingw53")
print(" android: android_x86, android_armv7")
exit(1)
def main():
parser = argparse.ArgumentParser(description='Install Qt SDK.', formatter_class=RawTextHelpFormatter, add_help=True)
parser.add_argument("qt_version", help="Qt version in the format of \"5.X.Y\"")
parser.add_argument('host', choices=['linux', 'mac', 'windows'], help="host os name")
parser.add_argument('target', choices=['desktop', 'android', 'ios'], help="target sdk")
parser.add_argument('arch', nargs='?', help="\ntarget linux/desktop: gcc_64"
"\ntarget mac/desktop: clang_64"
"\ntarget mac/ios: ios"
"\nwindows/desktop: win64_msvc2017_64, win64_msvc2015_64"
"\n in32_msvc2015, win32_mingw53"
"\nandroid: android_x86, android_armv7")
args = parser.parse_args()
arch = args.arch
if arch is None:
if os_name == "linux" and target == "desktop":
arch = "gcc_64"
elif os_name == "mac" and target == "desktop":
arch = "clang_64"
elif os_name == "mac" and target == "ios":
arch = "ios"
if arch == "":
print("Please supply a target architecture.")
args.print_help()
exit(1)
qt_version = args.qt_version
os_name = args.host
target = args.target
archives = QtArchives(os_name, qt_version, target, arch)
installer = QtInstaller(archives)
installer.install(qt_version, arch)
sys.stdout.write("\033[K")
print("Finished installation")
if __name__ == "__main__":
sys.exit(main())

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
six

22
setup.py Normal file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
import io
import os
from setuptools import setup
def readme():
with io.open(os.path.join(os.path.dirname(__file__),'README.rst'), mode="r", encoding="UTF-8") as f:
return f.read()
setup(name='aqtinstall',
version='0.2.0',
description='Another Qt installer',
url='http://github.com/miurahr/qli-installer',
license='MIT',
long_description=readme(),
author='Hioshi Miura',
author_email='miurahr@linux.com',
packages = ["aqt"],
scripts = ["aqtinst"]
)