mirror of
https://github.com/Hopiu/linkchecker.git
synced 2026-03-16 22:10:26 +00:00
Remove platform-specific installer stuff and ensure a build .whl wheel file can be built.
This commit is contained in:
parent
3d711666e1
commit
e3ab90246d
3 changed files with 10 additions and 498 deletions
31
Makefile
31
Makefile
|
|
@ -9,7 +9,6 @@ MAINTAINER:=$(shell $(PYTHON) setup.py --maintainer)
|
|||
LAPPNAME:=$(shell echo $(APPNAME)|tr "[A-Z]" "[a-z]")
|
||||
ARCHIVE_SOURCE_EXT:=gz
|
||||
ARCHIVE_SOURCE:=$(APPNAME)-$(VERSION).tar.$(ARCHIVE_SOURCE_EXT)
|
||||
ARCHIVE_WIN32:=$(APPNAME)-$(VERSION).exe
|
||||
GITUSER:=wummel
|
||||
GITREPO:=$(LAPPNAME)
|
||||
HOMEPAGE:=$(HOME)/public_html/$(LAPPNAME)-webpage.git
|
||||
|
|
@ -111,14 +110,9 @@ tag:
|
|||
git tag upstream/$(VERSION)
|
||||
git push --tags origin upstream/$(VERSION)
|
||||
|
||||
upload: upload_source upload_binary
|
||||
|
||||
upload_source:
|
||||
upload:
|
||||
twine upload dist/$(ARCHIVE_SOURCE) dist/$(ARCHIVE_SOURCE).asc
|
||||
|
||||
upload_binary:
|
||||
cp dist/$(ARCHIVE_WIN32) dist/$(ARCHIVE_WIN32).asc \
|
||||
$(HOMEPAGE)/dist
|
||||
|
||||
homepage:
|
||||
# update metadata
|
||||
|
|
@ -159,21 +153,6 @@ dist: locale MANIFEST chmod
|
|||
rm -f dist/$(ARCHIVE_SOURCE)
|
||||
$(PYTHON) setup.py sdist --formats=tar
|
||||
gzip --best dist/$(APPNAME)-$(VERSION).tar
|
||||
[ ! -f ../$(ARCHIVE_WIN32) ] || cp ../$(ARCHIVE_WIN32) dist
|
||||
|
||||
# Build OSX installer with py2app
|
||||
app: distclean localbuild chmod
|
||||
$(PYTHON) setup.py py2app $(PY2APPOPTS)
|
||||
|
||||
# Build RPM installer with cx_Freeze
|
||||
rpm:
|
||||
$(MAKE) -C doc/html
|
||||
$(MAKE) -C linkcheck/HtmlParser
|
||||
$(PYTHON) setup.py bdist_rpm
|
||||
|
||||
# Build portable Linux app
|
||||
binary: distclean localbuild chmod
|
||||
LINKCHECKER_FREEZE=1 $(PYTHON) setup.py bdist
|
||||
|
||||
# The check programs used here are mostly local scripts on my private system.
|
||||
# So for other developers there is no need to execute this target.
|
||||
|
|
@ -201,10 +180,6 @@ releasecheck: check
|
|||
@if egrep -i "xx\.|xxxx|\.xx" doc/changelog.txt > /dev/null; then \
|
||||
echo "Could not release: edit doc/changelog.txt release date"; false; \
|
||||
fi
|
||||
@if [ ! -f ../$(ARCHIVE_WIN32) ]; then \
|
||||
echo "Missing WIN32 distribution archive at ../$(ARCHIVE_WIN32)"; \
|
||||
false; \
|
||||
fi
|
||||
$(PYTHON) setup.py check --restructuredtext
|
||||
|
||||
sign:
|
||||
|
|
@ -218,7 +193,7 @@ test: localbuild
|
|||
pyflakes:
|
||||
pyflakes $(PY_FILES_DIRS) 2>&1 | \
|
||||
grep -v "local variable 'dummy' is assigned to but never used" | \
|
||||
grep -v -E "'(py2exe|py2app|PyQt4|biplist|setuptools|win32com|find_executable|parse_sitemap|parse_sitemapindex|parse_bookmark_data|parse_bookmark_file|wsgiref|pyftpdlib|linkchecker_rc)' imported but unused" | \
|
||||
grep -v -E "'(PyQt4|biplist|setuptools|win32com|find_executable|parse_sitemap|parse_sitemapindex|parse_bookmark_data|parse_bookmark_file|wsgiref|pyftpdlib|linkchecker_rc)' imported but unused" | \
|
||||
grep -v "undefined name '_'" | \
|
||||
grep -v "undefined name '_n'" | cat
|
||||
|
||||
|
|
@ -255,4 +230,4 @@ ide:
|
|||
.PHONY: test changelog gui count pyflakes ide login upload all clean distclean
|
||||
.PHONY: pep8 cleandeb locale localbuild deb diff dnsdiff sign
|
||||
.PHONY: filescheck update-copyright releasecheck check register announce
|
||||
.PHONY: chmod dist app rpm release homepage
|
||||
.PHONY: chmod dist release homepage
|
||||
|
|
|
|||
|
|
@ -10,3 +10,6 @@ provides = linkchecker
|
|||
group = Applications/Internet
|
||||
install_script = install-rpm.sh
|
||||
python = python
|
||||
|
||||
[bdist_wheel]
|
||||
universal = 0
|
||||
|
|
|
|||
474
setup.py
474
setup.py
|
|
@ -19,11 +19,6 @@
|
|||
Setup file for the distuils module.
|
||||
|
||||
It includes the following features:
|
||||
- py2exe support (including InnoScript installer generation)
|
||||
- py2app support (including DMG package generation)
|
||||
- cx_Freeze support
|
||||
- Qt plugin installation for py2exe and py2app
|
||||
- Microsoft Visual C++ DLL installation for py2exe
|
||||
- creation and installation of configuration files with installation data
|
||||
- automatic detection and usage of GNU99 standard for C compiler
|
||||
- automatic MANIFEST.in check
|
||||
|
|
@ -50,22 +45,8 @@ try:
|
|||
except NameError:
|
||||
unicode = lambda x: x
|
||||
|
||||
# if a frozen Unix application should be built with cx_Freeze
|
||||
do_freeze = int(os.environ.get('LINKCHECKER_FREEZE', '0'))
|
||||
|
||||
# import Distutils stuff
|
||||
try:
|
||||
# setuptools (which is needed by py2app) monkey-patches the
|
||||
# distutils.core.Command class.
|
||||
# So we need to import it before importing the distutils core
|
||||
import setuptools
|
||||
except ImportError:
|
||||
# ignore when setuptools is not installed
|
||||
setuptools = None
|
||||
if do_freeze:
|
||||
from cx_Freeze import setup, Executable
|
||||
else:
|
||||
from distutils.core import setup
|
||||
from setuptools import setup
|
||||
from distutils.core import Extension
|
||||
from distutils.command.install_lib import install_lib
|
||||
from distutils.command.build_ext import build_ext
|
||||
|
|
@ -74,29 +55,9 @@ from distutils.command.clean import clean
|
|||
from distutils.command.install_data import install_data
|
||||
from distutils.dir_util import remove_tree
|
||||
from distutils.file_util import write_file
|
||||
from distutils.spawn import find_executable
|
||||
from distutils import util, log
|
||||
try:
|
||||
# py2exe monkey-patches the distutils.core.Distribution class
|
||||
# So we need to import it before importing the Distribution class
|
||||
import py2exe
|
||||
has_py2exe = True
|
||||
except ImportError:
|
||||
# py2exe is not installed
|
||||
has_py2exe = False
|
||||
if do_freeze:
|
||||
from cx_Freeze.dist import Distribution, build, install_exe
|
||||
executables = [Executable("linkchecker"), Executable("linkchecker-gui")]
|
||||
else:
|
||||
from distutils.core import Distribution
|
||||
from distutils.command.build import build
|
||||
executables = None
|
||||
try:
|
||||
import py2app
|
||||
has_py2app = True
|
||||
except ImportError:
|
||||
# py2app is not installed
|
||||
has_py2app = False
|
||||
from distutils.core import Distribution
|
||||
from distutils.command.build import build
|
||||
|
||||
# the application version
|
||||
AppVersion = "9.4"
|
||||
|
|
@ -112,57 +73,6 @@ def get_long_description():
|
|||
except:
|
||||
return Description
|
||||
|
||||
# Microsoft Visual C++ runtime version (tested with Python 2.7.2)
|
||||
MSVCP90Version = '9.0.30729.6161'
|
||||
MSVCP90Suffix = 'x-ww_31a54e43'
|
||||
MSVCP90Token = '1fc8b3b9a1e18e3b'
|
||||
|
||||
# basic includes for py2exe and py2app
|
||||
py_includes = ['dns.rdtypes.IN.*', 'dns.rdtypes.ANY.*',
|
||||
'linkcheck.logger.*',
|
||||
]
|
||||
# basic excludes for py2exe and py2app
|
||||
py_excludes = ['doctest', 'unittest', 'argcomplete', 'Tkinter',
|
||||
'PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL',
|
||||
'PyQt4.QtScript', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml',
|
||||
'PyQt4.phonon',
|
||||
]
|
||||
# py2exe options for Windows packaging
|
||||
py2exe_options = dict(
|
||||
packages=["encodings"],
|
||||
excludes=py_excludes + ['win32com.gen_py'],
|
||||
# silence py2exe error about not finding msvcp90.dll
|
||||
dll_excludes=['MSVCP90.dll'],
|
||||
# add sip so that PyQt4 works
|
||||
# add PyQt4.QtSql so that sqlite needed by QHelpCollection works
|
||||
includes=py_includes + ["sip", "PyQt4.QtSql"],
|
||||
compressed=1,
|
||||
optimize=2,
|
||||
)
|
||||
# py2app options for OSX packaging
|
||||
py2app_options = dict(
|
||||
includes=py_includes + ['sip', 'PyQt4',
|
||||
'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtSql'],
|
||||
excludes=py_excludes,
|
||||
strip=True,
|
||||
optimize=2,
|
||||
iconfile='doc/html/favicon.icns',
|
||||
plist={
|
||||
'CFBundleIdentifier': 'org.pythonmac.%s' % AppName,
|
||||
'CFBundleIconFile': 'favicon.icns',
|
||||
},
|
||||
argv_emulation=True,
|
||||
)
|
||||
# cx_Freeze for Linux RPM packaging
|
||||
cx_includes = [x[:-2] for x in py_includes]
|
||||
cxfreeze_options = dict(
|
||||
packages=["encodings"],
|
||||
excludes=py_excludes,
|
||||
includes=cx_includes + ['sip', 'PyQt4',
|
||||
'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtSql'],
|
||||
)
|
||||
|
||||
|
||||
def normpath (path):
|
||||
"""Norm a path name to platform specific notation."""
|
||||
return os.path.normpath(path)
|
||||
|
|
@ -179,21 +89,6 @@ def cnormpath (path):
|
|||
return path
|
||||
|
||||
|
||||
def get_nt_platform_vars ():
|
||||
"""Return program file path and architecture for NT systems."""
|
||||
platform = util.get_platform()
|
||||
if platform == "win-amd64":
|
||||
# the Visual C++ runtime files are installed in the x86 directory
|
||||
progvar = "%ProgramFiles(x86)%"
|
||||
architecture = "amd64"
|
||||
elif platform == "win32":
|
||||
progvar = "%ProgramFiles%"
|
||||
architecture = "x86"
|
||||
else:
|
||||
raise ValueError("Unsupported platform %r" % platform)
|
||||
return os.path.expandvars(progvar), architecture
|
||||
|
||||
|
||||
release_ro = re.compile(r"\(released (.+)\)")
|
||||
def get_release_date ():
|
||||
"""Parse and return relase date as string from doc/changelog.txt."""
|
||||
|
|
@ -213,129 +108,6 @@ def get_portable():
|
|||
return os.environ.get('LINKCHECKER_PORTABLE', '0')
|
||||
|
||||
|
||||
def get_qt_plugin_dir_win ():
|
||||
"""Get Qt plugin dir on Windows systems."""
|
||||
import PyQt4
|
||||
return os.path.join(os.path.dirname(PyQt4.__file__), "plugins")
|
||||
|
||||
|
||||
def get_qt_plugin_dir_osx ():
|
||||
"""Get Qt plugin dir on OSX systems."""
|
||||
# note: works on Qt installed with homebrew
|
||||
qtbindir = os.path.dirname(os.path.realpath(find_executable("qmake")))
|
||||
return os.path.join(os.path.dirname(qtbindir), "plugins")
|
||||
|
||||
|
||||
def add_qt_plugin_file (files, plugin_dir, dirname, filename):
|
||||
"""Add one Qt plugin file to list of data files."""
|
||||
files.append((dirname, [os.path.join(plugin_dir, dirname, filename)]))
|
||||
|
||||
|
||||
def add_qt_plugin_files (files):
|
||||
"""Add needed Qt plugins to list of data files. Filename prefix and
|
||||
suffix are different for Windows and OSX."""
|
||||
if os.name == 'nt':
|
||||
plugin_dir = get_qt_plugin_dir_win()
|
||||
args = ("", "4.dll")
|
||||
elif sys.platform == 'darwin':
|
||||
plugin_dir = get_qt_plugin_dir_osx()
|
||||
args = ("lib", ".dylib")
|
||||
else:
|
||||
raise ValueError("unsupported qt plugin platform")
|
||||
# Copy needed sqlite plugin files to distribution directory.
|
||||
add_qt_plugin_file(files, plugin_dir, "sqldrivers", "%sqsqlite%s" % args)
|
||||
# Copy needed gif image plugin files to distribution directory.
|
||||
add_qt_plugin_file(files, plugin_dir, "imageformats", "%sqgif%s" % args)
|
||||
|
||||
|
||||
def fix_qt_plugins_py2app (dist_dir):
|
||||
"""Fix Qt plugin files installed in data_dir by moving them to
|
||||
app_dir/Plugins and change the install_name."""
|
||||
app_dir = os.path.join(dist_dir, '%s.app' % AppName, 'Contents')
|
||||
plugin_dir = os.path.join(app_dir, 'Plugins')
|
||||
data_dir = os.path.join(app_dir, 'Resources')
|
||||
qt_lib_dir = os.path.join(os.path.dirname(get_qt_plugin_dir_osx()), 'lib')
|
||||
# make target plugin directory
|
||||
os.mkdir(plugin_dir)
|
||||
qt_plugins = ('sqldrivers', 'imageformats')
|
||||
qt_modules = ('QtCore', 'QtGui', 'QtSql')
|
||||
for plugin in qt_plugins:
|
||||
target_dir = os.path.join(plugin_dir, plugin)
|
||||
# move libraries
|
||||
os.rename(os.path.join(data_dir, plugin), target_dir)
|
||||
# fix libraries
|
||||
for library in glob.glob("%s/*.dylib" % target_dir):
|
||||
for module in qt_modules:
|
||||
libpath = "%s.framework/Versions/4/%s" % (module, module)
|
||||
oldpath = os.path.join(qt_lib_dir, libpath)
|
||||
newpath = '@executable_path/../Frameworks/%s' % libpath
|
||||
args = ['install_name_tool', '-change', oldpath, newpath, library]
|
||||
subprocess.check_call(args)
|
||||
|
||||
|
||||
def generate_dmg_image (dist_dir):
|
||||
"""Generate .dmg image."""
|
||||
imgPath = os.path.join(dist_dir, "%s-%s.dmg" % (AppName, AppVersion))
|
||||
tmpImgPath = os.path.join(dist_dir, "%s.tmp.dmg" % AppName)
|
||||
print("*** generating temporary DMG image ***")
|
||||
args = ['hdiutil', 'create', '-srcfolder', dist_dir, '-fs', 'HFSX',
|
||||
'-volname', AppName, '-format', 'UDZO', tmpImgPath]
|
||||
subprocess.check_call(args)
|
||||
print("*** generating final DMG image ***")
|
||||
args = ['hdiutil', 'convert', tmpImgPath, '-format', 'UDZO',
|
||||
'-imagekey', 'zlib-level=9', '-o', imgPath]
|
||||
subprocess.check_call(args)
|
||||
os.remove(tmpImgPath)
|
||||
|
||||
|
||||
def sign_the_code (dist_dir):
|
||||
"""Sign the OSX application code."""
|
||||
app_dir = os.path.join(dist_dir, "%s.app" % AppName)
|
||||
args = ['codesign', '-s', myname, '-v', app_dir]
|
||||
print("*** signing the application code ***")
|
||||
try:
|
||||
subprocess.check_call(args)
|
||||
except subprocess.CalledProcessError as msg:
|
||||
print("WARN: codesigning failed", msg)
|
||||
|
||||
|
||||
def add_msvc_files (files):
|
||||
"""Add needed MSVC++ runtime files. Only Version 9.0.21022.8 is tested
|
||||
and can be downloaded here:
|
||||
http://www.microsoft.com/en-us/download/details.aspx?id=5582
|
||||
"""
|
||||
prog_dir, architecture = get_nt_platform_vars()
|
||||
dirname = "Microsoft.VC90.CRT"
|
||||
version = "%s_%s_%s" % (MSVCP90Token, MSVCP90Version, MSVCP90Suffix)
|
||||
args = (architecture, dirname, version)
|
||||
path = r'C:\Windows\WinSxS\%s_%s_%s\*.*' % args
|
||||
files.append((dirname, glob.glob(path)))
|
||||
# Copy the manifest file into the build directory and rename it
|
||||
# because it must have the same name as the directory.
|
||||
path = r'C:\Windows\WinSxS\Manifests\%s_%s_%s.manifest' % args
|
||||
target = os.path.join(os.getcwd(), 'build', '%s.manifest' % dirname)
|
||||
shutil.copy(path, target)
|
||||
files.append((dirname, [target]))
|
||||
|
||||
|
||||
def add_requests_cert_file(files):
|
||||
"""Add Python requests .pem file for installers."""
|
||||
import requests
|
||||
filename = os.path.join(os.path.dirname(requests.__file__), 'cacert.pem')
|
||||
dirname = 'share/linkchecker'
|
||||
files.append((dirname, [filename]))
|
||||
|
||||
|
||||
def insert_dns_path():
|
||||
"""Let py2exe, py2app and cx_Freeze find the dns package."""
|
||||
lib_dir = "lib.%s-%s" % (util.get_platform(), sys.version[0:3])
|
||||
if hasattr(sys, 'gettotalrefcount'):
|
||||
lib_dir += '-pydebug'
|
||||
dnspath = os.path.abspath(os.path.join('build', lib_dir, 'linkcheck_dns'))
|
||||
if dnspath not in sys.path:
|
||||
sys.path.insert(0, dnspath)
|
||||
|
||||
|
||||
class MyInstallLib (install_lib, object):
|
||||
"""Custom library installation."""
|
||||
|
||||
|
|
@ -418,33 +190,6 @@ class MyInstallData (install_data, object):
|
|||
os.chmod(path, mode)
|
||||
|
||||
|
||||
# Microsoft application manifest for linkchecker-gui.exe; see also
|
||||
# http://msdn.microsoft.com/en-us/library/aa374191%28VS.85%29.aspx
|
||||
app_manifest = """
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
|
||||
manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="%(appname)s"
|
||||
version="%(appversion)s.0.0"
|
||||
processorArchitecture="*"
|
||||
/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.VC90.CRT"
|
||||
version="%(msvcrtversion)s"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="%(msvcrttoken)s">
|
||||
</assemblyIdentity>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
||||
""" % dict(appversion=AppVersion, appname=AppName,
|
||||
msvcrtversion=MSVCP90Version, msvcrttoken=MSVCP90Token)
|
||||
|
||||
class MyDistribution (Distribution, object):
|
||||
"""Custom distribution class generating config file."""
|
||||
|
||||
|
|
@ -452,11 +197,6 @@ class MyDistribution (Distribution, object):
|
|||
"""Set console and windows scripts."""
|
||||
super(MyDistribution, self).__init__(attrs)
|
||||
self.console = ['linkchecker']
|
||||
self.windows = [{
|
||||
"script": "linkchecker-gui",
|
||||
"icon_resources": [(1, "doc/html/favicon.ico")],
|
||||
"other_resources": [(24, 1, app_manifest)],
|
||||
}]
|
||||
|
||||
def run_commands (self):
|
||||
"""Generate config file and run commands."""
|
||||
|
|
@ -650,7 +390,7 @@ data_files = [
|
|||
]
|
||||
|
||||
for (src, dst) in list_message_files(AppName):
|
||||
data_files.append((src, dst))
|
||||
data_files.append((dst, [src]))
|
||||
|
||||
if os.name == 'posix':
|
||||
data_files.append(('share/man/man1', ['doc/en/linkchecker.1', 'doc/en/linkchecker-gui.1']))
|
||||
|
|
@ -664,198 +404,6 @@ if os.name == 'posix':
|
|||
'doc/examples/check_urls.sh']))
|
||||
data_files.append(('share/applications', ['doc/linkchecker.desktop']))
|
||||
data_files.append(('share/applications', ['doc/linkchecker-gui.desktop']))
|
||||
if 'py2app' in sys.argv[1:]:
|
||||
if not has_py2app:
|
||||
raise SystemExit("py2app module could not be imported.")
|
||||
# add Qt plugins which are later fixed by fix_qt_plugins_py2app()
|
||||
add_qt_plugin_files(data_files)
|
||||
# needed for Qt to load the plugins
|
||||
data_files.append(('', ['osx/qt.conf']))
|
||||
add_requests_cert_file(data_files)
|
||||
insert_dns_path()
|
||||
elif 'py2exe' in sys.argv[1:]:
|
||||
if not has_py2exe:
|
||||
raise SystemExit("py2exe module could not be imported")
|
||||
add_qt_plugin_files(data_files)
|
||||
add_msvc_files(data_files)
|
||||
add_requests_cert_file(data_files)
|
||||
insert_dns_path()
|
||||
elif do_freeze:
|
||||
class MyInstallExe (install_exe, object):
|
||||
"""Install cx_Freeze executables."""
|
||||
def run (self):
|
||||
"""Add generated configuration to output files."""
|
||||
super(MyInstallExe, self).run()
|
||||
cmd_obj = self.distribution.get_command_obj("install_lib")
|
||||
cmd_obj.ensure_finalized()
|
||||
self.outfiles.append(cmd_obj.get_conf_output()+"c")
|
||||
insert_dns_path()
|
||||
|
||||
|
||||
class InnoScript:
|
||||
"""Class to generate INNO script."""
|
||||
|
||||
def __init__(self, lib_dir, dist_dir, windows_exe_files=[],
|
||||
console_exe_files=[], service_exe_files=[],
|
||||
comserver_files=[], lib_files=[]):
|
||||
"""Store INNO script infos."""
|
||||
self.lib_dir = lib_dir
|
||||
self.dist_dir = dist_dir
|
||||
if not self.dist_dir[-1] in "\\/":
|
||||
self.dist_dir += "\\"
|
||||
self.name = AppName
|
||||
self.version = AppVersion
|
||||
self.windows_exe_files = [self.chop(p) for p in windows_exe_files]
|
||||
self.console_exe_files = [self.chop(p) for p in console_exe_files]
|
||||
self.service_exe_files = [self.chop(p) for p in service_exe_files]
|
||||
self.comserver_files = [self.chop(p) for p in comserver_files]
|
||||
self.lib_files = [self.chop(p) for p in lib_files]
|
||||
self.icon = os.path.abspath(r'doc\html\favicon.ico')
|
||||
|
||||
def chop(self, pathname):
|
||||
"""Remove distribution directory from path name."""
|
||||
assert pathname.startswith(self.dist_dir)
|
||||
return pathname[len(self.dist_dir):]
|
||||
|
||||
def create(self, pathname=r"dist\omt.iss"):
|
||||
"""Create Inno script."""
|
||||
self.pathname = pathname
|
||||
self.distfilebase = "%s-%s" % (self.name, self.version)
|
||||
self.distfile = self.distfilebase + ".exe"
|
||||
with codecs.open(self.pathname, "w", 'utf-8-sig', 'strict') as fd:
|
||||
self.write_inno_script(fd)
|
||||
|
||||
def write_inno_script (self, fd):
|
||||
"""Write Inno script contents."""
|
||||
print("; WARNING: This script has been created by py2exe. Changes to this script", file=fd)
|
||||
print("; will be overwritten the next time py2exe is run!", file=fd)
|
||||
print("[Setup]", file=fd)
|
||||
print("AppName=%s" % self.name, file=fd)
|
||||
print("AppVerName=%s %s" % (self.name, self.version), file=fd)
|
||||
print(r"DefaultDirName={pf}\%s" % self.name, file=fd)
|
||||
print("DefaultGroupName=%s" % self.name, file=fd)
|
||||
print("OutputBaseFilename=%s" % self.distfilebase, file=fd)
|
||||
print("OutputDir=..", file=fd)
|
||||
print("SetupIconFile=%s" % self.icon, file=fd)
|
||||
print("UninstallDisplayIcon=%s" % self.icon, file=fd)
|
||||
print(file=fd)
|
||||
# Customize some messages
|
||||
print("[Messages]", file=fd)
|
||||
print("ConfirmUninstall=Are you sure you want to remove %1? Note that user-specific configuration files of %1 are not removed.", file=fd)
|
||||
print("BeveledLabel=DON'T PANIC", file=fd)
|
||||
print(file=fd)
|
||||
# List of source files
|
||||
files = self.windows_exe_files + \
|
||||
self.console_exe_files + \
|
||||
self.service_exe_files + \
|
||||
self.comserver_files + \
|
||||
self.lib_files
|
||||
print('[Files]', file=fd)
|
||||
for path in files:
|
||||
print(r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)), file=fd)
|
||||
print(file=fd)
|
||||
# Set icon filename
|
||||
print('[Icons]', file=fd)
|
||||
for path in self.windows_exe_files:
|
||||
print(r'Name: "{group}\%s"; Filename: "{app}\%s"' % \
|
||||
(self.name, path), file=fd)
|
||||
print(r'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name, file=fd)
|
||||
print(file=fd)
|
||||
# Uninstall registry keys
|
||||
print('[Registry]', file=fd)
|
||||
print(r'Root: HKCU; Subkey: "Software\Bastian\LinkChecker"; Flags: uninsdeletekey', file=fd)
|
||||
print(file=fd)
|
||||
# Uninstall optional log files
|
||||
print('[UninstallDelete]', file=fd)
|
||||
for path in (self.windows_exe_files + self.console_exe_files):
|
||||
exename = os.path.basename(path)
|
||||
print(r'Type: files; Name: "{pf}\%s\%s.log"' % (self.name, exename), file=fd)
|
||||
print(file=fd)
|
||||
|
||||
def compile (self):
|
||||
"""Compile Inno script with iscc.exe."""
|
||||
progpath = get_nt_platform_vars()[0]
|
||||
cmd = r'%s\Inno Setup 5\iscc.exe' % progpath
|
||||
subprocess.check_call([cmd, self.pathname])
|
||||
|
||||
def sign (self):
|
||||
"""Sign InnoSetup installer with local self-signed certificate."""
|
||||
print("*** signing the inno setup installer ***")
|
||||
pfxfile = r'windows\linkchecker.pfx'
|
||||
if os.path.isfile(pfxfile):
|
||||
path = get_windows_sdk_path()
|
||||
signtool = os.path.join(path, "bin", "signtool.exe")
|
||||
if os.path.isfile(signtool):
|
||||
cmd = [signtool, 'sign', '/f', pfxfile, self.distfile]
|
||||
subprocess.check_call(cmd)
|
||||
else:
|
||||
print("No signed installer: signtool.exe not found.")
|
||||
else:
|
||||
print("No signed installer: certificate %s not found." % pfxfile)
|
||||
|
||||
def get_windows_sdk_path():
|
||||
"""Return path of Microsoft Windows SDK installation, or None if
|
||||
not found."""
|
||||
try:
|
||||
import _winreg as winreg
|
||||
except ImportError:
|
||||
import winreg
|
||||
sub_key = r"Software\Microsoft\Microsoft SDKs\Windows"
|
||||
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, sub_key) as key:
|
||||
name = "CurrentInstallFolder"
|
||||
return winreg.QueryValueEx(key, name)[0]
|
||||
return None
|
||||
|
||||
try:
|
||||
from py2exe.build_exe import py2exe as py2exe_build
|
||||
|
||||
class MyPy2exe (py2exe_build):
|
||||
"""First builds the exe file(s), then creates a Windows installer.
|
||||
Needs InnoSetup to be installed."""
|
||||
|
||||
def run (self):
|
||||
"""Generate py2exe installer."""
|
||||
# First, let py2exe do it's work.
|
||||
py2exe_build.run(self)
|
||||
print("*** preparing the inno setup script ***")
|
||||
lib_dir = self.lib_dir
|
||||
dist_dir = self.dist_dir
|
||||
# create the Installer, using the files py2exe has created.
|
||||
script = InnoScript(lib_dir, dist_dir, self.windows_exe_files,
|
||||
self.console_exe_files, self.service_exe_files,
|
||||
self.comserver_files, self.lib_files)
|
||||
print("*** creating the inno setup script ***")
|
||||
script.create()
|
||||
print("*** compiling the inno setup script ***")
|
||||
script.compile()
|
||||
script.sign()
|
||||
except ImportError:
|
||||
class MyPy2exe:
|
||||
"""Dummy py2exe class."""
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
from py2app.build_app import py2app as py2app_build
|
||||
|
||||
class MyPy2app (py2app_build):
|
||||
"""First builds the app file(s), then creates a DMG installer.
|
||||
Needs hdiutil to be installed."""
|
||||
|
||||
def run (self):
|
||||
"""Generate py2app installer."""
|
||||
# First, let py2app do it's work.
|
||||
py2app_build.run(self)
|
||||
# Fix install names for Qt plugin libraries.
|
||||
fix_qt_plugins_py2app(self.dist_dir)
|
||||
sign_the_code(self.dist_dir)
|
||||
generate_dmg_image(self.dist_dir)
|
||||
|
||||
except ImportError:
|
||||
class MyPy2app:
|
||||
"""Dummy py2app class."""
|
||||
pass
|
||||
|
||||
|
||||
args = dict(
|
||||
name = AppName,
|
||||
|
|
@ -877,8 +425,6 @@ args = dict(
|
|||
'build': MyBuild,
|
||||
'clean': MyClean,
|
||||
'sdist': MySdist,
|
||||
'py2exe': MyPy2exe,
|
||||
'py2app': MyPy2app,
|
||||
},
|
||||
package_dir = {
|
||||
'linkcheck_dns.dns': 'third_party/dnspython/dns',
|
||||
|
|
@ -934,9 +480,6 @@ args = dict(
|
|||
'Programming Language :: C',
|
||||
],
|
||||
options = {
|
||||
"py2exe": py2exe_options,
|
||||
"py2app": py2app_options,
|
||||
"build_exe": cxfreeze_options,
|
||||
},
|
||||
# Requirements, usable with setuptools or the new Python packaging module.
|
||||
# Commented out since they are untested and not officially supported.
|
||||
|
|
@ -948,13 +491,4 @@ args = dict(
|
|||
# "Memory debugging": ['meliae'], # https://launchpad.net/meliae
|
||||
#}
|
||||
)
|
||||
if sys.platform == 'darwin':
|
||||
args["app"] = ['linkchecker-gui']
|
||||
if executables:
|
||||
args["executables"] = executables
|
||||
args["cmdclass"]["install_exe"] = MyInstallExe
|
||||
if setuptools is not None:
|
||||
args['install_requires'] = [
|
||||
'requests >= 2.2.0',
|
||||
]
|
||||
setup(**args)
|
||||
|
|
|
|||
Loading…
Reference in a new issue