Switch to setuptools and cleanup metadata.
py2exe support is gone for now, will be restored later.
This commit is contained in:
parent
bf9bf5e9b0
commit
bf9f45b380
5 changed files with 45 additions and 672 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,16 +1,12 @@
|
||||||
*.orig
|
*.orig
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
/*.egg
|
||||||
/Comics
|
/Comics
|
||||||
/build
|
/build
|
||||||
/dist
|
/dist
|
||||||
/.achievements
|
|
||||||
/MANIFEST
|
|
||||||
/todo
|
|
||||||
/Changelog.dosage*
|
/Changelog.dosage*
|
||||||
/_dosage_configdata.py
|
|
||||||
/comics.test
|
|
||||||
/testresults.txt
|
/testresults.txt
|
||||||
/dosage.prof
|
/dosage.prof
|
||||||
/test.sh
|
/dosage.egg-info
|
||||||
/scripts/*.json
|
/scripts/*.json
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
include MANIFEST.in
|
exclude .git*
|
||||||
include COPYING Makefile requirements.txt
|
exclude .travis.yml
|
||||||
include doc/Makefile doc/*.txt doc/*.1 doc/*.html doc/*.md doc/dosage-completion
|
recursive-exclude scripts dosage.*
|
||||||
include doc/css/*.css doc/js/*.js
|
|
||||||
include scripts/*.py scripts/*.sh scripts/*.bat scripts/*.iss
|
|
||||||
recursive-include tests *.py
|
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
# Copyright (C) 2012-2014 Bastian Kleineidam
|
# Copyright (C) 2012-2014 Bastian Kleineidam
|
||||||
|
# Copyright (C) 2015 Tobias Gruetzmacher
|
||||||
"""
|
"""
|
||||||
Define basic configuration data like version or application name.
|
Define basic configuration data like version or application name.
|
||||||
"""
|
"""
|
||||||
import _dosage_configdata as configdata
|
|
||||||
|
|
||||||
Version = configdata.version
|
AppName = u'dosage'
|
||||||
ReleaseDate = configdata.release_date
|
Version = u'2.16' # Should be PEP 440 compatible
|
||||||
AppName = configdata.name
|
App = AppName + u' ' + Version
|
||||||
App = AppName+u" "+Version
|
Maintainer = u'Tobias Gruetzmacher'
|
||||||
Author = configdata.author
|
MaintainerEmail = u'tobias-dosage@23.gs'
|
||||||
HtmlAuthor = Author.replace(u' ', u' ')
|
Url = u'http://dosage.rocks/'
|
||||||
Maintainer = configdata.maintainer
|
SupportUrl = u'https://github.com/webcomics/dosage/issues'
|
||||||
HtmlMaintainer = Maintainer.replace(u' ', u' ')
|
|
||||||
Copyright = u"Copyright (C) 2004-2008 " + \
|
|
||||||
(u",".join(Author.split(",")[:2]))+u" (C) 2012-2014 "+Maintainer
|
|
||||||
HtmlCopyright = u"Copyright © 2004-2008 " + \
|
|
||||||
(u",".join(HtmlAuthor.split(",")[:2]))+u" © 2012-2014 "+HtmlMaintainer
|
|
||||||
Url = configdata.url
|
|
||||||
SupportUrl = Url + u"issues"
|
|
||||||
Email = configdata.maintainer_email
|
|
||||||
UserAgent = u"Mozilla/5.0 (compatible; %s/%s; +%s)" % (AppName, Version, Url)
|
UserAgent = u"Mozilla/5.0 (compatible; %s/%s; +%s)" % (AppName, Version, Url)
|
||||||
Freeware = AppName+u""" comes with ABSOLUTELY NO WARRANTY!
|
Copyright = u"""Copyright (C) 2004-2005 Tristan Seligmann and Jonathan Jacobs
|
||||||
|
Copyright (C) 2012-2014 Bastian Kleineidam
|
||||||
|
Copyright (C) 2015 Tobias Gruetzmacher
|
||||||
|
"""
|
||||||
|
Freeware = AppName + u""" comes with ABSOLUTELY NO WARRANTY!
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions. Look at the file `COPYING' within this
|
under certain conditions. Look at the file `COPYING' within this
|
||||||
distribution."""
|
distribution."""
|
||||||
|
|
|
@ -1,219 +0,0 @@
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Inno Setup Ver: 5.4.2
|
|
||||||
// Script Version: 1.4.2
|
|
||||||
// Author: Jared Breland <jbreland@legroom.net>
|
|
||||||
// Homepage: http://www.legroom.net/software
|
|
||||||
// License: GNU Lesser General Public License (LGPL), version 3
|
|
||||||
// http://www.gnu.org/licenses/lgpl.html
|
|
||||||
//
|
|
||||||
// Script Function:
|
|
||||||
// Allow modification of environmental path directly from Inno Setup installers
|
|
||||||
//
|
|
||||||
// Instructions:
|
|
||||||
// Copy modpath.iss to the same directory as your setup script
|
|
||||||
//
|
|
||||||
// Add this statement to your [Setup] section
|
|
||||||
// ChangesEnvironment=true
|
|
||||||
//
|
|
||||||
// Add this statement to your [Tasks] section
|
|
||||||
// You can change the Description or Flags
|
|
||||||
// You can change the Name, but it must match the ModPathName setting below
|
|
||||||
// Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
|
|
||||||
//
|
|
||||||
// Add the following to the end of your [Code] section
|
|
||||||
// ModPathName defines the name of the task defined above
|
|
||||||
// ModPathType defines whether the 'user' or 'system' path will be modified;
|
|
||||||
// this will default to user if anything other than system is set
|
|
||||||
// setArrayLength must specify the total number of dirs to be added
|
|
||||||
// Result[0] contains first directory, Result[1] contains second, etc.
|
|
||||||
// const
|
|
||||||
// ModPathName = 'modifypath';
|
|
||||||
// ModPathType = 'user';
|
|
||||||
//
|
|
||||||
// function ModPathDir(): TArrayOfString;
|
|
||||||
// begin
|
|
||||||
// setArrayLength(Result, 1);
|
|
||||||
// Result[0] := ExpandConstant('{app}');
|
|
||||||
// end;
|
|
||||||
// #include "modpath.iss"
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
procedure ModPath();
|
|
||||||
var
|
|
||||||
oldpath: String;
|
|
||||||
newpath: String;
|
|
||||||
updatepath: Boolean;
|
|
||||||
pathArr: TArrayOfString;
|
|
||||||
aExecFile: String;
|
|
||||||
aExecArr: TArrayOfString;
|
|
||||||
i, d: Integer;
|
|
||||||
pathdir: TArrayOfString;
|
|
||||||
regroot: Integer;
|
|
||||||
regpath: String;
|
|
||||||
|
|
||||||
begin
|
|
||||||
// Get constants from main script and adjust behavior accordingly
|
|
||||||
// ModPathType MUST be 'system' or 'user'; force 'user' if invalid
|
|
||||||
if ModPathType = 'system' then begin
|
|
||||||
regroot := HKEY_LOCAL_MACHINE;
|
|
||||||
regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
|
|
||||||
end else begin
|
|
||||||
regroot := HKEY_CURRENT_USER;
|
|
||||||
regpath := 'Environment';
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Get array of new directories and act on each individually
|
|
||||||
pathdir := ModPathDir();
|
|
||||||
for d := 0 to GetArrayLength(pathdir)-1 do begin
|
|
||||||
updatepath := true;
|
|
||||||
|
|
||||||
// Modify WinNT path
|
|
||||||
if UsingWinNT() = true then begin
|
|
||||||
|
|
||||||
// Get current path, split into an array
|
|
||||||
RegQueryStringValue(regroot, regpath, 'Path', oldpath);
|
|
||||||
oldpath := oldpath + ';';
|
|
||||||
i := 0;
|
|
||||||
|
|
||||||
while (Pos(';', oldpath) > 0) do begin
|
|
||||||
SetArrayLength(pathArr, i+1);
|
|
||||||
pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
|
|
||||||
oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
|
|
||||||
i := i + 1;
|
|
||||||
|
|
||||||
// Check if current directory matches app dir
|
|
||||||
if pathdir[d] = pathArr[i-1] then begin
|
|
||||||
// if uninstalling, remove dir from path
|
|
||||||
if IsUninstaller() = true then begin
|
|
||||||
continue;
|
|
||||||
// if installing, flag that dir already exists in path
|
|
||||||
end else begin
|
|
||||||
updatepath := false;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Add current directory to new path
|
|
||||||
if i = 1 then begin
|
|
||||||
newpath := pathArr[i-1];
|
|
||||||
end else begin
|
|
||||||
newpath := newpath + ';' + pathArr[i-1];
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Append app dir to path if not already included
|
|
||||||
if (IsUninstaller() = false) AND (updatepath = true) then
|
|
||||||
newpath := newpath + ';' + pathdir[d];
|
|
||||||
|
|
||||||
// Write new path
|
|
||||||
RegWriteStringValue(regroot, regpath, 'Path', newpath);
|
|
||||||
|
|
||||||
// Modify Win9x path
|
|
||||||
end else begin
|
|
||||||
|
|
||||||
// Convert to shortened dirname
|
|
||||||
pathdir[d] := GetShortName(pathdir[d]);
|
|
||||||
|
|
||||||
// If autoexec.bat exists, check if app dir already exists in path
|
|
||||||
aExecFile := 'C:\AUTOEXEC.BAT';
|
|
||||||
if FileExists(aExecFile) then begin
|
|
||||||
LoadStringsFromFile(aExecFile, aExecArr);
|
|
||||||
for i := 0 to GetArrayLength(aExecArr)-1 do begin
|
|
||||||
if IsUninstaller() = false then begin
|
|
||||||
// If app dir already exists while installing, skip add
|
|
||||||
if (Pos(pathdir[d], aExecArr[i]) > 0) then
|
|
||||||
updatepath := false;
|
|
||||||
break;
|
|
||||||
end else begin
|
|
||||||
// If app dir exists and = what we originally set, then delete at uninstall
|
|
||||||
if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
|
|
||||||
aExecArr[i] := '';
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
|
|
||||||
if (IsUninstaller() = false) AND (updatepath = true) then begin
|
|
||||||
SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
|
|
||||||
|
|
||||||
// If uninstalling, write the full autoexec out
|
|
||||||
end else begin
|
|
||||||
SaveStringsToFile(aExecFile, aExecArr, False);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Split a string into an array using passed delimeter
|
|
||||||
procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
i := 0;
|
|
||||||
repeat
|
|
||||||
SetArrayLength(Dest, i+1);
|
|
||||||
if Pos(Separator,Text) > 0 then begin
|
|
||||||
Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
|
|
||||||
Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
|
|
||||||
i := i + 1;
|
|
||||||
end else begin
|
|
||||||
Dest[i] := Text;
|
|
||||||
Text := '';
|
|
||||||
end;
|
|
||||||
until Length(Text)=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure CurStepChanged(CurStep: TSetupStep);
|
|
||||||
var
|
|
||||||
taskname: String;
|
|
||||||
begin
|
|
||||||
taskname := ModPathName;
|
|
||||||
if CurStep = ssPostInstall then
|
|
||||||
if IsTaskSelected(taskname) then
|
|
||||||
ModPath();
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
|
||||||
var
|
|
||||||
aSelectedTasks: TArrayOfString;
|
|
||||||
i: Integer;
|
|
||||||
taskname: String;
|
|
||||||
regpath: String;
|
|
||||||
regstring: String;
|
|
||||||
appid: String;
|
|
||||||
begin
|
|
||||||
// only run during actual uninstall
|
|
||||||
if CurUninstallStep = usUninstall then begin
|
|
||||||
// get list of selected tasks saved in registry at install time
|
|
||||||
appid := '{#emit SetupSetting("AppId")}';
|
|
||||||
if appid = '' then appid := '{#emit SetupSetting("AppName")}';
|
|
||||||
regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
|
|
||||||
RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
|
|
||||||
if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
|
|
||||||
|
|
||||||
// check each task; if matches modpath taskname, trigger patch removal
|
|
||||||
if regstring <> '' then begin
|
|
||||||
taskname := ModPathName;
|
|
||||||
MPExplode(aSelectedTasks, regstring, ',');
|
|
||||||
if GetArrayLength(aSelectedTasks) > 0 then begin
|
|
||||||
for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
|
|
||||||
if comparetext(aSelectedTasks[i], taskname) = 0 then
|
|
||||||
ModPath();
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function NeedRestart(): Boolean;
|
|
||||||
var
|
|
||||||
taskname: String;
|
|
||||||
begin
|
|
||||||
taskname := ModPathName;
|
|
||||||
if IsTaskSelected(taskname) and not UsingWinNT() then begin
|
|
||||||
Result := True;
|
|
||||||
end else begin
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
end;
|
|
451
setup.py
451
setup.py
|
@ -2,409 +2,12 @@
|
||||||
# -*- coding: iso-8859-1 -*-
|
# -*- coding: iso-8859-1 -*-
|
||||||
# Copyright (C) 2004-2005 Tristan Seligmann and Jonathan Jacobs
|
# Copyright (C) 2004-2005 Tristan Seligmann and Jonathan Jacobs
|
||||||
# Copyright (C) 2012-2014 Bastian Kleineidam
|
# Copyright (C) 2012-2014 Bastian Kleineidam
|
||||||
"""
|
# Copyright (C) 2015 Tobias Gruetzmacher
|
||||||
Setup file for the distuils module.
|
|
||||||
|
|
||||||
It includes the following features:
|
|
||||||
- py2exe support (including InnoScript installer generation)
|
|
||||||
- Microsoft Visual C++ DLL installation for py2exe
|
|
||||||
- creation and installation of configuration files with installation data
|
|
||||||
- automatic MANIFEST.in check
|
|
||||||
|
|
||||||
"""
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import codecs
|
import codecs
|
||||||
import re
|
from setuptools import setup, find_packages
|
||||||
import glob
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import warnings
|
|
||||||
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
|
|
||||||
from distutils.core import setup, Distribution
|
|
||||||
from distutils.command.install_lib import install_lib
|
|
||||||
from distutils.command.register import register
|
|
||||||
from distutils import util
|
|
||||||
from distutils.file_util import write_file
|
|
||||||
|
|
||||||
AppVersion = '2.16'
|
|
||||||
AppName = 'dosage'
|
|
||||||
|
|
||||||
py_excludes = ['doctest', 'unittest', 'Tkinter', 'pdb',
|
|
||||||
'email', 'ftplib', 'pickle',
|
|
||||||
]
|
|
||||||
py_includes = ['dosagelib.plugins.*']
|
|
||||||
# py2exe options for Windows packaging
|
|
||||||
py2exe_options = dict(
|
|
||||||
packages=["encodings"],
|
|
||||||
excludes=py_excludes,
|
|
||||||
includes=py_includes,
|
|
||||||
# silence py2exe error about not finding msvcp90.dll
|
|
||||||
dll_excludes=['MSVCP90.dll'],
|
|
||||||
compressed=1,
|
|
||||||
optimize=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
warnings.filterwarnings("ignore", r"Unknown distribution option")
|
|
||||||
|
|
||||||
def normpath (path):
|
|
||||||
"""Norm a path name to platform specific notation."""
|
|
||||||
return os.path.normpath(path)
|
|
||||||
|
|
||||||
|
|
||||||
def cnormpath (path):
|
|
||||||
"""Norm a path name to platform specific notation and make it absolute."""
|
|
||||||
path = normpath(path)
|
|
||||||
if os.name == 'nt':
|
|
||||||
# replace slashes with backslashes
|
|
||||||
path = path.replace("/", "\\")
|
|
||||||
if not os.path.isabs(path):
|
|
||||||
path = normpath(os.path.join(sys.prefix, path))
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
release_ro = re.compile(r"\(released (.+)\)")
|
|
||||||
def get_release_date ():
|
|
||||||
"""Parse and return relase date as string from doc/changelog.txt."""
|
|
||||||
fname = os.path.join("doc", "changelog.txt")
|
|
||||||
release_date = "unknown"
|
|
||||||
with open(fname) as fd:
|
|
||||||
# the release date is on the first line
|
|
||||||
line = fd.readline()
|
|
||||||
mo = release_ro.search(line)
|
|
||||||
if mo:
|
|
||||||
release_date = mo.groups(1)
|
|
||||||
return release_date
|
|
||||||
|
|
||||||
|
|
||||||
# Microsoft Visual C++ runtime version (tested with Python 2.7.2)
|
|
||||||
MSVCP90Version = '9.0.21022.8'
|
|
||||||
MSVCP90Token = '1fc8b3b9a1e18e3b'
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
data_files = []
|
|
||||||
else:
|
|
||||||
data_files = [('share/man/man1', ['doc/dosage.1'])]
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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=29
|
|
||||||
"""
|
|
||||||
prog_dir, architecture = get_nt_platform_vars()
|
|
||||||
dirname = "Microsoft.VC90.CRT"
|
|
||||||
version = "%s_%s_x-ww_d08d0375" % (MSVCP90Token, MSVCP90Version)
|
|
||||||
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]))
|
|
||||||
|
|
||||||
|
|
||||||
if 'py2exe' in sys.argv[1:]:
|
|
||||||
if not has_py2exe:
|
|
||||||
raise SystemExit("py2exe module could not be imported")
|
|
||||||
add_msvc_files(data_files)
|
|
||||||
|
|
||||||
|
|
||||||
class MyInstallLib (install_lib, object):
|
|
||||||
"""Custom library installation."""
|
|
||||||
|
|
||||||
def install (self):
|
|
||||||
"""Install the generated config file."""
|
|
||||||
outs = super(MyInstallLib, self).install()
|
|
||||||
infile = self.create_conf_file()
|
|
||||||
outfile = os.path.join(self.install_dir, os.path.basename(infile))
|
|
||||||
self.copy_file(infile, outfile)
|
|
||||||
outs.append(outfile)
|
|
||||||
return outs
|
|
||||||
|
|
||||||
def create_conf_file (self):
|
|
||||||
"""Create configuration file."""
|
|
||||||
cmd_obj = self.distribution.get_command_obj("install")
|
|
||||||
cmd_obj.ensure_finalized()
|
|
||||||
# we have to write a configuration file because we need the
|
|
||||||
# <install_data> directory (and other stuff like author, url, ...)
|
|
||||||
# all paths are made absolute by cnormpath()
|
|
||||||
data = []
|
|
||||||
for d in ['purelib', 'platlib', 'lib', 'headers', 'scripts', 'data']:
|
|
||||||
attr = 'install_%s' % d
|
|
||||||
if cmd_obj.root:
|
|
||||||
# cut off root path prefix
|
|
||||||
cutoff = len(cmd_obj.root)
|
|
||||||
# don't strip the path separator
|
|
||||||
if cmd_obj.root.endswith(os.sep):
|
|
||||||
cutoff -= 1
|
|
||||||
val = getattr(cmd_obj, attr)[cutoff:]
|
|
||||||
else:
|
|
||||||
val = getattr(cmd_obj, attr)
|
|
||||||
if attr == 'install_data':
|
|
||||||
cdir = os.path.join(val, "share", "dosage")
|
|
||||||
data.append('config_dir = %r' % cnormpath(cdir))
|
|
||||||
elif attr == 'install_lib':
|
|
||||||
if cmd_obj.root:
|
|
||||||
_drive, tail = os.path.splitdrive(val)
|
|
||||||
if tail.startswith(os.sep):
|
|
||||||
tail = tail[1:]
|
|
||||||
self.install_lib = os.path.join(cmd_obj.root, tail)
|
|
||||||
else:
|
|
||||||
self.install_lib = val
|
|
||||||
data.append("%s = %r" % (attr, cnormpath(val)))
|
|
||||||
self.distribution.create_conf_file(data, directory=self.install_lib)
|
|
||||||
return self.get_conf_output()
|
|
||||||
|
|
||||||
def get_conf_output (self):
|
|
||||||
"""Get filename for distribution configuration file."""
|
|
||||||
return self.distribution.get_conf_filename(self.install_lib)
|
|
||||||
|
|
||||||
def get_outputs (self):
|
|
||||||
"""Add the generated config file to the list of outputs."""
|
|
||||||
outs = super(MyInstallLib, self).get_outputs()
|
|
||||||
conf_output = self.get_conf_output()
|
|
||||||
outs.append(conf_output)
|
|
||||||
if self.compile:
|
|
||||||
outs.extend(self._bytecode_filenames([conf_output]))
|
|
||||||
return outs
|
|
||||||
|
|
||||||
|
|
||||||
class MyDistribution (Distribution, object):
|
|
||||||
"""Custom distribution class generating config file."""
|
|
||||||
|
|
||||||
def __init__ (self, attrs):
|
|
||||||
"""Set console and windows scripts."""
|
|
||||||
super(MyDistribution, self).__init__(attrs)
|
|
||||||
self.console = ['dosage']
|
|
||||||
|
|
||||||
def run_commands (self):
|
|
||||||
"""Generate config file and run commands."""
|
|
||||||
cwd = os.getcwd()
|
|
||||||
data = []
|
|
||||||
data.append('config_dir = %r' % os.path.join(cwd, "config"))
|
|
||||||
data.append("install_data = %r" % cwd)
|
|
||||||
data.append("install_scripts = %r" % cwd)
|
|
||||||
self.create_conf_file(data)
|
|
||||||
super(MyDistribution, self).run_commands()
|
|
||||||
|
|
||||||
def get_conf_filename (self, directory):
|
|
||||||
"""Get name for config file."""
|
|
||||||
return os.path.join(directory, "_%s_configdata.py" % self.get_name())
|
|
||||||
|
|
||||||
def create_conf_file (self, data, directory=None):
|
|
||||||
"""Create local config file from given data (list of lines) in
|
|
||||||
the directory (or current directory if not given)."""
|
|
||||||
data.insert(0, "# this file is automatically created by setup.py")
|
|
||||||
data.insert(0, "# -*- coding: iso-8859-1 -*-")
|
|
||||||
if directory is None:
|
|
||||||
directory = os.getcwd()
|
|
||||||
filename = self.get_conf_filename(directory)
|
|
||||||
# add metadata
|
|
||||||
metanames = ("name", "version", "author", "author_email",
|
|
||||||
"maintainer", "maintainer_email", "url",
|
|
||||||
"license", "description", "long_description",
|
|
||||||
"keywords", "platforms", "fullname", "contact",
|
|
||||||
"contact_email")
|
|
||||||
for name in metanames:
|
|
||||||
method = "get_" + name
|
|
||||||
val = getattr(self.metadata, method)()
|
|
||||||
data.append("%s = %r" % (name, val))
|
|
||||||
data.append('release_date = "%s"' % get_release_date())
|
|
||||||
# write the config file
|
|
||||||
util.execute(write_file, (filename, data),
|
|
||||||
"creating %s" % filename, self.verbose >= 1, self.dry_run)
|
|
||||||
|
|
||||||
|
|
||||||
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.lname = AppName.lower()
|
|
||||||
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\icon\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."""
|
|
||||||
print("*** creating the inno setup script ***")
|
|
||||||
self.pathname = pathname
|
|
||||||
self.distfilebase = "%s-%s" % (self.name, self.version)
|
|
||||||
self.distfile = self.distfilebase + ".exe"
|
|
||||||
with open(self.pathname, "w") 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("ChangesEnvironment=true", 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(file=fd)
|
|
||||||
print("[Tasks]", file=fd)
|
|
||||||
print("Name: modifypath; Description: Add application directory to %PATH%", 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)
|
|
||||||
# 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)
|
|
||||||
for path in self.console_exe_files:
|
|
||||||
name = os.path.basename(path).capitalize()
|
|
||||||
print(r'Name: "{group}\%s help"; Filename: "cmd.exe"; Parameters: "/K %s --help"' % (name, path), file=fd)
|
|
||||||
print(r'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name, file=fd)
|
|
||||||
print(file=fd)
|
|
||||||
# Uninstall optional log files
|
|
||||||
print('[UninstallDelete]', file=fd)
|
|
||||||
for path in (self.console_exe_files + self.windows_exe_files):
|
|
||||||
exename = os.path.basename(path)
|
|
||||||
print(r'Type: files; Name: "{pf}\%s\%s.log"' % (self.lname, exename), file=fd)
|
|
||||||
print(file=fd)
|
|
||||||
# Add app dir to PATH
|
|
||||||
print("[Code]", file=fd)
|
|
||||||
print("""\
|
|
||||||
const
|
|
||||||
ModPathName = 'modifypath';
|
|
||||||
ModPathType = 'user';
|
|
||||||
|
|
||||||
function ModPathDir(): TArrayOfString;
|
|
||||||
begin
|
|
||||||
setArrayLength(Result, 1)
|
|
||||||
Result[0] := ExpandConstant('{app}');
|
|
||||||
end;
|
|
||||||
#include "modpath.iss"
|
|
||||||
""", file=fd)
|
|
||||||
shutil.copy(r"scripts\modpath.iss", "dist")
|
|
||||||
|
|
||||||
def compile (self):
|
|
||||||
"""Compile Inno script with iscc.exe."""
|
|
||||||
print("*** compiling the inno setup script ***")
|
|
||||||
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'scripts\%s.pfx' % self.lname
|
|
||||||
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)
|
|
||||||
script.create()
|
|
||||||
script.compile()
|
|
||||||
script.sign()
|
|
||||||
except ImportError:
|
|
||||||
class MyPy2exe:
|
|
||||||
"""Dummy py2exe class."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MyRegister (register, object):
|
|
||||||
"""Custom register command."""
|
|
||||||
|
|
||||||
def build_post_data(self, action):
|
|
||||||
"""Force application name to lower case."""
|
|
||||||
data = super(MyRegister, self).build_post_data(action)
|
|
||||||
data['name'] = data['name'].lower()
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def get_authors():
|
def get_authors():
|
||||||
"""Read list of authors from a text file, filtering comments."""
|
"""Read list of authors from a text file, filtering comments."""
|
||||||
|
@ -418,48 +21,48 @@ def get_authors():
|
||||||
return u", ".join(authors)
|
return u", ".join(authors)
|
||||||
|
|
||||||
|
|
||||||
args = dict(
|
config = {}
|
||||||
name = AppName,
|
with codecs.open(os.path.join('dosagelib', 'configuration.py')) as fp:
|
||||||
version = AppVersion,
|
exec(fp.read(), config)
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name = config['AppName'],
|
||||||
|
version = config['Version'],
|
||||||
description = 'a comic strip downloader and archiver',
|
description = 'a comic strip downloader and archiver',
|
||||||
keywords = 'comic,webcomic,downloader,archiver',
|
keywords = 'comic,webcomic,downloader,archiver',
|
||||||
author = get_authors(),
|
author = get_authors(),
|
||||||
maintainer = 'Bastian Kleineidam',
|
maintainer = config['Maintainer'],
|
||||||
maintainer_email = 'bastian.kleineidam@web.de',
|
maintainer_email = config['MaintainerEmail'],
|
||||||
license = 'MIT',
|
license = 'MIT',
|
||||||
url = 'http://wummel.github.io/dosage/',
|
url = config['Url'],
|
||||||
packages = (
|
packages = find_packages(exclude=['tests']),
|
||||||
'dosagelib',
|
|
||||||
'dosagelib.plugins',
|
|
||||||
),
|
|
||||||
data_files = data_files,
|
|
||||||
scripts = (
|
scripts = (
|
||||||
'dosage',
|
'dosage',
|
||||||
),
|
),
|
||||||
distclass = MyDistribution,
|
|
||||||
cmdclass = {
|
|
||||||
'install_lib': MyInstallLib,
|
|
||||||
'py2exe': MyPy2exe,
|
|
||||||
'register': MyRegister,
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
"py2exe": py2exe_options,
|
|
||||||
},
|
|
||||||
classifiers = (
|
classifiers = (
|
||||||
'Environment :: Console',
|
'Environment :: Console',
|
||||||
'Intended Audience :: End Users/Desktop',
|
'Intended Audience :: End Users/Desktop',
|
||||||
'Topic :: Multimedia :: Graphics',
|
'Topic :: Multimedia :: Graphics',
|
||||||
'Topic :: Internet :: WWW/HTTP',
|
'Topic :: Internet :: WWW/HTTP',
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'License :: OSI Approved :: GNU General Public License (GPL)',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
|
'Programming Language :: Python :: 2',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
),
|
),
|
||||||
install_requires = (
|
install_requires = (
|
||||||
'requests',
|
'requests',
|
||||||
'pycountry',
|
'pycountry',
|
||||||
)
|
),
|
||||||
|
extras_require = {
|
||||||
|
'xpath': ["lxml"],
|
||||||
|
'css': ['cssselect'],
|
||||||
|
},
|
||||||
|
setup_requires = [
|
||||||
|
"setuptools_git >= 1.0",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
setup(**args)
|
|
||||||
|
|
Loading…
Reference in a new issue