Merge pull request #2159 from nicozanf/master
Change binary scripts to use PyInstaller with PY3
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
The files in this folder must be run from the main web2py folder.
|
||||
They are for building windows and osx binary distribution and not meant for the end user.
|
||||
4
extras/build_web2py/README.md
Normal file
4
extras/build_web2py/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# build-web2py
|
||||
|
||||
The files in this folder must be run from the main web2py folder.
|
||||
They are for building windows and osx binary distribution using PyInstaller and not meant for the end user.
|
||||
164
extras/build_web2py/build_web2py.py
Normal file
164
extras/build_web2py/build_web2py.py
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# up to 2019, we have used py2applet, py2exe and bbfreeze for building web2py binaries
|
||||
# The original scripts can be found on GitHub for web2py up to version 2.18.4
|
||||
# See also Niphlod's work on http://www.web2pyslices.com/slice/show/1726/build-windows-binaries
|
||||
# Then we switched to Pyinstaller in order to fully support Python 3
|
||||
|
||||
from distutils.core import setup
|
||||
from gluon.import_all import base_modules, contributed_modules
|
||||
from gluon.fileutils import readlines_file
|
||||
from glob import glob
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import re
|
||||
import zipfile
|
||||
import subprocess
|
||||
import platform
|
||||
|
||||
|
||||
USAGE = """
|
||||
build_web2py - make web2py Windows and MacOS binaries with pyinstaller
|
||||
Usage:
|
||||
Install the pyinstaller program, copy this file (plus web2py.*.spec files)
|
||||
to web2py root folder and run:
|
||||
|
||||
python build_py3.py
|
||||
|
||||
(tested with python 3.7.3 and 2.7.16 with PyInstaller 3.4)
|
||||
"""
|
||||
BUILD_DEBUG = False
|
||||
"""
|
||||
If BUILD_DEBUG is set to False, no gluon modules will be embedded inside the binary web2py.exe.
|
||||
Thus, you can easily update the build version by changing the gluon folder inside the resulting ZIP file.
|
||||
In case of problem , set BUILD_DEBUG to True. Then all the gluon modules will be analyzed and embedded, too.
|
||||
You can later analyze the .exe with 'pyi-archive_viewer web2py.exe' and then 'o PYZ-00.pyz'
|
||||
in order to check for missing system modules to be manually inserted in the SPEC file
|
||||
"""
|
||||
|
||||
if len(sys.argv) != 1 or not os.path.isfile('web2py.py'):
|
||||
print(USAGE)
|
||||
sys.exit(1)
|
||||
os_version = platform.system()
|
||||
if os_version not in ('Windows', 'Darwin'):
|
||||
print('Unsupported system: %s' % os_version)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def unzip(source_filename, dest_dir):
|
||||
with zipfile.ZipFile(source_filename) as zf:
|
||||
zf.extractall(dest_dir)
|
||||
|
||||
# borrowed from http://bytes.com/topic/python/answers/851018-how-zip-directory-python-using-zipfile
|
||||
|
||||
|
||||
def recursive_zip(zipf, directory, folder=""):
|
||||
for item in os.listdir(directory):
|
||||
if os.path.isfile(os.path.join(directory, item)):
|
||||
zipf.write(os.path.join(directory, item), folder + os.sep + item)
|
||||
elif os.path.isdir(os.path.join(directory, item)):
|
||||
recursive_zip(
|
||||
zipf, os.path.join(directory, item), folder + os.sep + item)
|
||||
|
||||
|
||||
# read web2py version from VERSION file
|
||||
web2py_version_line = readlines_file('VERSION')[0]
|
||||
# use regular expression to get just the version number
|
||||
v_re = re.compile('[0-9]+\.[0-9]+\.[0-9]+')
|
||||
web2py_version = v_re.search(web2py_version_line).group(0)
|
||||
|
||||
# Python base version
|
||||
python_version = sys.version_info[:3]
|
||||
|
||||
|
||||
if os_version == 'Windows':
|
||||
print("\nBuilding binary web2py for Windows\n")
|
||||
if BUILD_DEBUG: # debug only
|
||||
subprocess.call('pyinstaller --clean --icon=extras/icons/web2py.ico \
|
||||
--hidden-import=site-packages --hidden-import=gluon.packages.dal.pydal \
|
||||
--hidden-import=gluon.packages.yatl.yatl web2py.py')
|
||||
zip_filename = 'web2py_win_debug'
|
||||
else: # normal run
|
||||
subprocess.call('pyinstaller --clean web2py.win.spec')
|
||||
subprocess.call('pyinstaller --clean web2py.win_no_console.spec')
|
||||
source_no_console = 'dist/web2py_no_console/'
|
||||
files = 'web2py_no_console.exe'
|
||||
shutil.move(os.path.join(source_no_console, files), 'dist')
|
||||
shutil.rmtree(source_no_console)
|
||||
shutil.rmtree('build')
|
||||
zip_filename = 'web2py_win'
|
||||
|
||||
source = 'dist/web2py/'
|
||||
for files in os.listdir(source):
|
||||
shutil.move(os.path.join(source, files), 'dist')
|
||||
shutil.rmtree(source)
|
||||
os.unlink('dist/web2py.exe.manifest')
|
||||
|
||||
|
||||
|
||||
bin_folders = ['dist',]
|
||||
|
||||
|
||||
elif os_version == 'Darwin':
|
||||
print("\nBuilding binary web2py for MacOS\n")
|
||||
|
||||
if BUILD_DEBUG: #debug only
|
||||
subprocess.call("pyinstaller --clean --icon=extras/icons/web2py.icns --hidden-import=gluon.packages.dal.pydal --hidden-import=gluon.packages.yatl.yatl \
|
||||
--hidden-import=site-packages --windowed web2py.py", shell=True)
|
||||
zip_filename = 'web2py_osx_debug'
|
||||
else: # normal run
|
||||
subprocess.call("pyinstaller --clean web2py.mac.spec", shell=True)
|
||||
# cleanup + move binary files to dist folder
|
||||
#shutil.rmtree(os.path.join('dist', 'web2py'))
|
||||
shutil.rmtree('build')
|
||||
zip_filename = 'web2py_osx'
|
||||
|
||||
shutil.move((os.path.join('dist', 'web2py')),(os.path.join('dist', 'web2py_cmd')))
|
||||
bin_folders = [(os.path.join('dist', 'web2py.app/Contents/MacOS')), (os.path.join('dist', 'web2py_cmd'))]
|
||||
print("\nWeb2py binary successfully built!\n")
|
||||
|
||||
|
||||
# add data_files
|
||||
for req in ['CHANGELOG', 'LICENSE', 'VERSION']:
|
||||
for bin_folder in bin_folders:
|
||||
shutil.copy(req, os.path.join(bin_folder, req))
|
||||
# cleanup unuseful binary cache
|
||||
for dirpath, dirnames, files in os.walk('.'):
|
||||
if dirpath.endswith('__pycache__'):
|
||||
print('Deleting cached binary directory : %s' % dirpath)
|
||||
shutil.rmtree(dirpath)
|
||||
for dirpath, dirnames, files in os.walk('.'):
|
||||
for file in files:
|
||||
if file.endswith('.pyc'):
|
||||
print('Deleting cached binary file : %s' % file)
|
||||
os.unlink(os.path.join(dirpath, file))
|
||||
|
||||
print("\nPreparing package ...")
|
||||
# misc
|
||||
for folders in ['gluon', 'extras', 'site-packages', 'scripts', 'applications', 'examples', 'handlers']:
|
||||
for bin_folder in bin_folders:
|
||||
shutil.copytree(folders, os.path.join(bin_folder, folders))
|
||||
if not os.path.exists(os.path.join(bin_folder, 'logs')):
|
||||
os.mkdir(os.path.join(bin_folder, 'logs'))
|
||||
|
||||
|
||||
# create a web2py folder & copy dist's files into it
|
||||
shutil.copytree('dist', 'zip_temp/web2py')
|
||||
# create zip file
|
||||
zipf = zipfile.ZipFile(zip_filename + ".zip",
|
||||
"w", compression=zipfile.ZIP_DEFLATED)
|
||||
# just temp so the web2py directory is included in our zip file
|
||||
path = 'zip_temp'
|
||||
# leave the first folder as None, as path is root.
|
||||
recursive_zip(zipf, path)
|
||||
zipf.close()
|
||||
shutil.rmtree('zip_temp')
|
||||
shutil.rmtree('dist')
|
||||
|
||||
|
||||
print("Your binary version of web2py can be found in " + \
|
||||
zip_filename + ".zip")
|
||||
print("You may extract the archive anywhere and then run web2py without worrying about dependency")
|
||||
print("\nEnjoy binary web2py " + web2py_version_line + "\n with embedded Python " + sys.version + "\n")
|
||||
@@ -1,160 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This is a setup.py script generated by py2applet
|
||||
|
||||
Usage:
|
||||
python setup.py py2app
|
||||
"""
|
||||
|
||||
copy_apps = False
|
||||
copy_scripts = True
|
||||
copy_site_packages = True
|
||||
remove_build_files = True
|
||||
make_zip = True
|
||||
zip_filename = "web2py_osx"
|
||||
|
||||
from setuptools import setup
|
||||
from gluon.import_all import base_modules, contributed_modules
|
||||
from gluon.fileutils import readlines_file
|
||||
import os
|
||||
import fnmatch
|
||||
import shutil
|
||||
import sys
|
||||
import re
|
||||
import zipfile
|
||||
|
||||
#read web2py version from VERSION file
|
||||
web2py_version_line = readlines_file('VERSION')[0]
|
||||
#use regular expression to get just the version number
|
||||
v_re = re.compile('[0-9]+\.[0-9]+\.[0-9]+')
|
||||
web2py_version = v_re.search(web2py_version_line).group(0)
|
||||
|
||||
class reglob:
|
||||
def __init__(self, directory, pattern="*"):
|
||||
self.stack = [directory]
|
||||
self.pattern = pattern
|
||||
self.files = []
|
||||
self.index = 0
|
||||
|
||||
def __getitem__(self, index):
|
||||
while 1:
|
||||
try:
|
||||
file = self.files[self.index]
|
||||
self.index = self.index + 1
|
||||
except IndexError:
|
||||
self.index = 0
|
||||
self.directory = self.stack.pop()
|
||||
self.files = os.listdir(self.directory)
|
||||
else:
|
||||
fullname = os.path.join(self.directory, file)
|
||||
if os.path.isdir(fullname) and not os.path.islink(fullname):
|
||||
self.stack.append(fullname)
|
||||
if not (file.startswith('.') or file.startswith('#') or file.endswith('~')) \
|
||||
and fnmatch.fnmatch(file, self.pattern):
|
||||
return fullname
|
||||
|
||||
setup(app=['web2py.py'],
|
||||
version=web2py_version,
|
||||
description="web2py web framework",
|
||||
author="Massimo DiPierro",
|
||||
license="LGPL v3",
|
||||
data_files=[
|
||||
'NEWINSTALL',
|
||||
'ABOUT',
|
||||
'LICENSE',
|
||||
'VERSION',
|
||||
'splashlogo.gif',
|
||||
'logging.example.conf',
|
||||
'options_std.py',
|
||||
],
|
||||
options={'py2app': {
|
||||
'argv_emulation': True,
|
||||
'includes': base_modules,
|
||||
}},
|
||||
setup_requires=['py2app'])
|
||||
|
||||
|
||||
def copy_folders(source, destination):
|
||||
"""Copy files & folders from source to destination (within dist/)"""
|
||||
print 'copying %s -> %s' % (source, destination)
|
||||
base = 'dist/web2py.app/Contents/Resources/'
|
||||
if os.path.exists(os.path.join(base, destination)):
|
||||
shutil.rmtree(os.path.join(base, destination))
|
||||
shutil.copytree(os.path.join(source), os.path.join(base, destination))
|
||||
|
||||
#Should we include applications?
|
||||
copy_folders('gluon','gluon')
|
||||
|
||||
if copy_apps:
|
||||
copy_folders('applications', 'applications')
|
||||
print "Your application(s) have been added"
|
||||
else:
|
||||
#only copy web2py's default applications
|
||||
copy_folders('applications/admin', 'applications/admin')
|
||||
copy_folders('applications/welcome', 'applications/welcome')
|
||||
copy_folders('applications/examples', 'applications/examples')
|
||||
print "Only web2py's admin, examples & welcome applications have been added"
|
||||
|
||||
|
||||
#should we copy project's site-packages into dist/site-packages
|
||||
if copy_site_packages:
|
||||
#copy site-packages
|
||||
copy_folders('site-packages', 'site-packages')
|
||||
else:
|
||||
#no worries, web2py will create the (empty) folder first run
|
||||
print "Skipping site-packages"
|
||||
pass
|
||||
|
||||
#should we copy project's scripts into dist/scripts
|
||||
if copy_scripts:
|
||||
#copy scripts
|
||||
copy_folders('scripts', 'scripts')
|
||||
else:
|
||||
#no worries, web2py will create the (empty) folder first run
|
||||
print "Skipping scripts"
|
||||
pass
|
||||
|
||||
|
||||
#borrowed from http://bytes.com/topic/python/answers/851018-how-zip-directory-python-using-zipfile
|
||||
def recursive_zip(zipf, directory, folder=""):
|
||||
for item in os.listdir(directory):
|
||||
if os.path.isfile(os.path.join(directory, item)):
|
||||
zipf.write(os.path.join(directory, item), folder + os.sep + item)
|
||||
elif os.path.isdir(os.path.join(directory, item)):
|
||||
recursive_zip(
|
||||
zipf, os.path.join(directory, item), folder + os.sep + item)
|
||||
|
||||
#should we create a zip file of the build?
|
||||
|
||||
if make_zip:
|
||||
#to keep consistent with how official web2py windows zip file is setup,
|
||||
#create a web2py folder & copy dist's files into it
|
||||
shutil.copytree('dist', 'zip_temp/web2py')
|
||||
#create zip file
|
||||
#use filename specified via command line
|
||||
zipf = zipfile.ZipFile(
|
||||
zip_filename + ".zip", "w", compression=zipfile.ZIP_DEFLATED)
|
||||
path = 'zip_temp' # just temp so the web2py directory is included in our zip file
|
||||
recursive_zip(
|
||||
zipf, path) # leave the first folder as None, as path is root.
|
||||
zipf.close()
|
||||
shutil.rmtree('zip_temp')
|
||||
print "Your Windows binary version of web2py can be found in " + \
|
||||
zip_filename + ".zip"
|
||||
print "You may extract the archive anywhere and then run web2py/web2py.exe"
|
||||
|
||||
#should py2exe build files be removed?
|
||||
if remove_build_files:
|
||||
shutil.rmtree('build')
|
||||
shutil.rmtree('deposit')
|
||||
shutil.rmtree('dist')
|
||||
print "py2exe build files removed"
|
||||
|
||||
#final info
|
||||
if not make_zip and not remove_build_files:
|
||||
print "Your Windows binary & associated files can also be found in /dist"
|
||||
|
||||
print "Finished!"
|
||||
print "Enjoy web2py " + web2py_version_line
|
||||
@@ -1,27 +0,0 @@
|
||||
[Setup]
|
||||
#py2exe often includes DLLS from windows which aren't licensed for
|
||||
#open source distribution. Should they be removed?
|
||||
remove_microsoft_dlls: Yes
|
||||
|
||||
#copy all web2py apps currently installed?
|
||||
#If no, only the default admin, welcome & example apps will be included
|
||||
copy_apps: No
|
||||
|
||||
#include the web2py\site-packages directory?
|
||||
copy_site_packages: Yes
|
||||
|
||||
#include the web2py\scripts directory?
|
||||
copy_scripts: Yes
|
||||
|
||||
#create a zip file of the build for easy distribution?
|
||||
make_zip: Yes
|
||||
|
||||
#what should the zip file be named? (leave off the .zip extension)
|
||||
zip_filename = web2py_win
|
||||
|
||||
#should the build, deposit & dist directories used by py2exe be removed?
|
||||
#if you created a zip file you likely don't need these directories anymore
|
||||
remove_build_files = Yes
|
||||
|
||||
#should the build include the gevented webserver (needs gevent)
|
||||
include_gevent = Yes
|
||||
@@ -1,232 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Adapted from http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/view/head:/static/scripts/tools/standalone_exe.py
|
||||
|
||||
USAGE = """
|
||||
Usage:
|
||||
Copy this and setup_exe.conf to web2py root folder
|
||||
To build with py2exe:
|
||||
Install py2exe: http://sourceforge.net/projects/py2exe/files/
|
||||
run python setup_exe.py py2exe
|
||||
To build with bbfreeze:
|
||||
Install bbfreeze: https://pypi.python.org/pypi/bbfreeze/
|
||||
run python setup_exe.py bbfreeze
|
||||
"""
|
||||
|
||||
from distutils.core import setup
|
||||
from gluon.import_all import base_modules, contributed_modules
|
||||
from gluon.fileutils import readlines_file
|
||||
from glob import glob
|
||||
import fnmatch
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import re
|
||||
import zipfile
|
||||
|
||||
if len(sys.argv) != 2 or not os.path.isfile('web2py.py'):
|
||||
print USAGE
|
||||
sys.exit(1)
|
||||
BUILD_MODE = sys.argv[1]
|
||||
if not BUILD_MODE in ('py2exe', 'bbfreeze'):
|
||||
print USAGE
|
||||
sys.exit(1)
|
||||
|
||||
def unzip(source_filename, dest_dir):
|
||||
with zipfile.ZipFile(source_filename) as zf:
|
||||
zf.extractall(dest_dir)
|
||||
|
||||
#borrowed from http://bytes.com/topic/python/answers/851018-how-zip-directory-python-using-zipfile
|
||||
def recursive_zip(zipf, directory, folder=""):
|
||||
for item in os.listdir(directory):
|
||||
if os.path.isfile(os.path.join(directory, item)):
|
||||
zipf.write(os.path.join(directory, item), folder + os.sep + item)
|
||||
elif os.path.isdir(os.path.join(directory, item)):
|
||||
recursive_zip(
|
||||
zipf, os.path.join(directory, item), folder + os.sep + item)
|
||||
|
||||
|
||||
#read web2py version from VERSION file
|
||||
web2py_version_line = readlines_file('VERSION')[0]
|
||||
#use regular expression to get just the version number
|
||||
v_re = re.compile('[0-9]+\.[0-9]+\.[0-9]+')
|
||||
web2py_version = v_re.search(web2py_version_line).group(0)
|
||||
|
||||
#pull in preferences from config file
|
||||
import ConfigParser
|
||||
Config = ConfigParser.ConfigParser()
|
||||
Config.read('setup_exe.conf')
|
||||
remove_msft_dlls = Config.getboolean("Setup", "remove_microsoft_dlls")
|
||||
copy_apps = Config.getboolean("Setup", "copy_apps")
|
||||
copy_site_packages = Config.getboolean("Setup", "copy_site_packages")
|
||||
copy_scripts = Config.getboolean("Setup", "copy_scripts")
|
||||
make_zip = Config.getboolean("Setup", "make_zip")
|
||||
zip_filename = Config.get("Setup", "zip_filename")
|
||||
remove_build_files = Config.getboolean("Setup", "remove_build_files")
|
||||
include_gevent = Config.getboolean("Setup", "include_gevent")
|
||||
|
||||
# Python base version
|
||||
python_version = sys.version_info[:3]
|
||||
|
||||
|
||||
|
||||
if BUILD_MODE == 'py2exe':
|
||||
import py2exe
|
||||
|
||||
setup(
|
||||
console=[{'script':'web2py.py',
|
||||
'icon_resources': [(0, 'extras/icons/web2py.ico')]
|
||||
}],
|
||||
windows=[{'script':'web2py.py',
|
||||
'icon_resources': [(1, 'extras/icons/web2py.ico')],
|
||||
'dest_base':'web2py_no_console' # MUST NOT be just 'web2py' otherwise it overrides the standard web2py.exe
|
||||
}],
|
||||
name="web2py",
|
||||
version=web2py_version,
|
||||
description="web2py web framework",
|
||||
author="Massimo DiPierro",
|
||||
license="LGPL v3",
|
||||
data_files=[
|
||||
'ABOUT',
|
||||
'LICENSE',
|
||||
'VERSION'
|
||||
],
|
||||
options={'py2exe': {
|
||||
'packages': contributed_modules,
|
||||
'includes': base_modules,
|
||||
}},
|
||||
)
|
||||
#py2exe packages lots of duplicates in the library.zip, let's save some space
|
||||
library_temp_dir = os.path.join('dist', 'library_temp')
|
||||
library_zip_archive = os.path.join('dist', 'library.zip')
|
||||
os.makedirs(library_temp_dir)
|
||||
unzip(library_zip_archive, library_temp_dir)
|
||||
os.unlink(library_zip_archive)
|
||||
zipl = zipfile.ZipFile(library_zip_archive, "w", compression=zipfile.ZIP_DEFLATED)
|
||||
recursive_zip(zipl, library_temp_dir)
|
||||
zipl.close()
|
||||
shutil.rmtree(library_temp_dir)
|
||||
print "web2py binary successfully built"
|
||||
|
||||
elif BUILD_MODE == 'bbfreeze':
|
||||
modules = base_modules + contributed_modules
|
||||
from bbfreeze import Freezer
|
||||
f = Freezer(distdir="dist", includes=(modules))
|
||||
f.addScript("web2py.py")
|
||||
#to make executable without GUI we need this trick
|
||||
shutil.copy("web2py.py", "web2py_no_console.py")
|
||||
f.addScript("web2py_no_console.py", gui_only=True)
|
||||
if include_gevent:
|
||||
#fetch the gevented webserver script and copy to root
|
||||
gevented_webserver = os.path.join("handlers", "web2py_on_gevent.py")
|
||||
shutil.copy(gevented_webserver, "web2py_on_gevent.py")
|
||||
f.addScript("web2py_on_gevent.py")
|
||||
f.setIcon('extras/icons/web2py.ico')
|
||||
f() # starts the freezing process
|
||||
os.unlink("web2py_no_console.py")
|
||||
if include_gevent:
|
||||
os.unlink("web2py_on_gevent.py")
|
||||
#add data_files
|
||||
for req in ['ABOUT', 'LICENSE', 'VERSION']:
|
||||
shutil.copy(req, os.path.join('dist', req))
|
||||
print "web2py binary successfully built"
|
||||
|
||||
try:
|
||||
os.unlink('storage.sqlite')
|
||||
except:
|
||||
pass
|
||||
|
||||
#This need to happen after bbfreeze is run because Freezer() deletes distdir before starting!
|
||||
if python_version > (2,5):
|
||||
# Python26 compatibility: http://www.py2exe.org/index.cgi/Tutorial#Step52
|
||||
try:
|
||||
shutil.copytree('C:\Bin\Microsoft.VC90.CRT', 'dist/Microsoft.VC90.CRT/')
|
||||
except:
|
||||
print "You MUST copy Microsoft.VC90.CRT folder into the archive"
|
||||
|
||||
def copy_folders(source, destination):
|
||||
"""Copy files & folders from source to destination (within dist/)"""
|
||||
if os.path.exists(os.path.join('dist', destination)):
|
||||
shutil.rmtree(os.path.join('dist', destination))
|
||||
shutil.copytree(os.path.join(source), os.path.join('dist', destination))
|
||||
|
||||
#should we remove Windows OS dlls user is unlikely to be able to distribute
|
||||
if remove_msft_dlls:
|
||||
print "Deleted Microsoft files not licensed for open source distribution"
|
||||
print "You are still responsible for making sure you have the rights to distribute any other included files!"
|
||||
#delete the API-MS-Win-Core DLLs
|
||||
for f in glob('dist/API-MS-Win-*.dll'):
|
||||
os.unlink(f)
|
||||
#then delete some other files belonging to Microsoft
|
||||
other_ms_files = ['KERNELBASE.dll', 'MPR.dll', 'MSWSOCK.dll',
|
||||
'POWRPROF.dll']
|
||||
for f in other_ms_files:
|
||||
try:
|
||||
os.unlink(os.path.join('dist', f))
|
||||
except:
|
||||
print "unable to delete dist/" + f
|
||||
|
||||
#Should we include applications?
|
||||
if copy_apps:
|
||||
copy_folders('applications', 'applications')
|
||||
print "Your application(s) have been added"
|
||||
else:
|
||||
#only copy web2py's default applications
|
||||
copy_folders('applications/admin', 'applications/admin')
|
||||
copy_folders('applications/welcome', 'applications/welcome')
|
||||
copy_folders('applications/examples', 'applications/examples')
|
||||
print "Only web2py's admin, examples & welcome applications have been added"
|
||||
|
||||
copy_folders('extras', 'extras')
|
||||
copy_folders('examples', 'examples')
|
||||
copy_folders('handlers', 'handlers')
|
||||
|
||||
|
||||
#should we copy project's site-packages into dist/site-packages
|
||||
if copy_site_packages:
|
||||
#copy site-packages
|
||||
copy_folders('site-packages', 'site-packages')
|
||||
else:
|
||||
#no worries, web2py will create the (empty) folder first run
|
||||
print "Skipping site-packages"
|
||||
|
||||
#should we copy project's scripts into dist/scripts
|
||||
if copy_scripts:
|
||||
#copy scripts
|
||||
copy_folders('scripts', 'scripts')
|
||||
else:
|
||||
#no worries, web2py will create the (empty) folder first run
|
||||
print "Skipping scripts"
|
||||
|
||||
#should we create a zip file of the build?
|
||||
if make_zip:
|
||||
#create a web2py folder & copy dist's files into it
|
||||
shutil.copytree('dist', 'zip_temp/web2py')
|
||||
#create zip file
|
||||
zipf = zipfile.ZipFile(zip_filename + ".zip",
|
||||
"w", compression=zipfile.ZIP_DEFLATED)
|
||||
# just temp so the web2py directory is included in our zip file
|
||||
path = 'zip_temp'
|
||||
# leave the first folder as None, as path is root.
|
||||
recursive_zip(zipf, path)
|
||||
zipf.close()
|
||||
shutil.rmtree('zip_temp')
|
||||
print "Your Windows binary version of web2py can be found in " + \
|
||||
zip_filename + ".zip"
|
||||
print "You may extract the archive anywhere and then run web2py/web2py.exe"
|
||||
|
||||
#should py2exe build files be removed?
|
||||
if remove_build_files:
|
||||
if BUILD_MODE == 'py2exe':
|
||||
shutil.rmtree('build')
|
||||
shutil.rmtree('deposit')
|
||||
shutil.rmtree('dist')
|
||||
print "build files removed"
|
||||
|
||||
#final info
|
||||
if not make_zip and not remove_build_files:
|
||||
print "Your Windows binary & associated files can also be found in /dist"
|
||||
|
||||
print "Finished!"
|
||||
print "Enjoy web2py " + web2py_version_line
|
||||
52
extras/build_web2py/web2py.mac.spec
Normal file
52
extras/build_web2py/web2py.mac.spec
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['web2py.py'],
|
||||
pathex=['.'],
|
||||
binaries=[('/System/Library/Frameworks/Tk.framework/Tk', 'tk'), ('/System/Library/Frameworks/Tcl.framework/Tcl', 'tcl')],
|
||||
datas=[],
|
||||
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'cProfile', 'csv', 'ctypes.wintypes',
|
||||
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
|
||||
'ipaddress', 'imaplib', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
|
||||
'psycopg2', 'psycopg2._ipaddress', 'psycopg2._json', 'psycopg2._range', 'psycopg2.extensions', 'psycopg2.extras', 'psycopg2.sql',
|
||||
'psycopg2.tz', 'pyodbc', 'python-ldap', 'rlcompleter', 'sched', 'site', 'smtplib', 'sqlite3', 'sqlite3.dbapi2', 'sqlite3.dump', 'timeit', 'tkinter',
|
||||
'tkinter.commondialog', 'tkinter.constants', 'tkinter.messagebox', 'uuid', 'win32evtlogutil', 'wsgiref',
|
||||
'wsgiref.handlers', 'wsgiref.headers', 'wsgiref.simple_server', 'wsgiref.util', 'xml.dom', 'xml.dom.NodeFilter', 'xml.dom.domreg',
|
||||
'xml.dom.expatbuilder', 'xml.dom.minicompat', 'xml.dom.minidom', 'xml.dom.pulldom', 'xml.dom.xmlbuilder', 'xmlrpc.server'],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=['gluon'],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='web2py',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
icon='extras/icons/web2py.icns')
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='web2py')
|
||||
app = BUNDLE(coll,
|
||||
name='web2py.app',
|
||||
icon='extras/icons/web2py.icns',
|
||||
bundle_identifier=None,
|
||||
info_plist={
|
||||
'NSPrincipleClass': 'NSApplication',
|
||||
'NSAppleScriptEnabled': False})
|
||||
44
extras/build_web2py/web2py.win.spec
Normal file
44
extras/build_web2py/web2py.win.spec
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['web2py.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'csv', 'ctypes.wintypes',
|
||||
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
|
||||
'ipaddress', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
|
||||
'psycopg2', 'psycopg2._ipaddress', 'psycopg2._json', 'psycopg2._range', 'psycopg2.extensions', 'psycopg2.extras', 'psycopg2.sql',
|
||||
'psycopg2.tz', 'pyodbc', 'python-ldap', 'rlcompleter', 'sched', 'site', 'smtplib', 'sqlite3', 'sqlite3.dbapi2', 'sqlite3.dump', 'timeit', 'tkinter',
|
||||
'tkinter.commondialog', 'tkinter.constants', 'tkinter.messagebox', 'uuid', 'win32con', 'win32evtlogutil', 'winerror', 'wsgiref',
|
||||
'wsgiref.handlers', 'wsgiref.headers', 'wsgiref.simple_server', 'wsgiref.util', 'xml.dom', 'xml.dom.NodeFilter', 'xml.dom.domreg',
|
||||
'xml.dom.expatbuilder', 'xml.dom.minicompat', 'xml.dom.minidom', 'xml.dom.pulldom', 'xml.dom.xmlbuilder', 'xmlrpc.server'],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=['gluon'],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='web2py',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=True , icon='extras\\icons\\web2py.ico')
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='web2py')
|
||||
44
extras/build_web2py/web2py.win_no_console.spec
Normal file
44
extras/build_web2py/web2py.win_no_console.spec
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['web2py.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'csv', 'ctypes.wintypes',
|
||||
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
|
||||
'ipaddress', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
|
||||
'psycopg2', 'psycopg2._ipaddress', 'psycopg2._json', 'psycopg2._range', 'psycopg2.extensions', 'psycopg2.extras', 'psycopg2.sql',
|
||||
'psycopg2.tz', 'pyodbc', 'python-ldap', 'rlcompleter', 'sched', 'site', 'smtplib', 'sqlite3', 'sqlite3.dbapi2', 'sqlite3.dump', 'timeit', 'tkinter',
|
||||
'tkinter.commondialog', 'tkinter.constants', 'tkinter.messagebox', 'uuid', 'win32con', 'win32evtlogutil', 'winerror', 'wsgiref',
|
||||
'wsgiref.handlers', 'wsgiref.headers', 'wsgiref.simple_server', 'wsgiref.util', 'xml.dom', 'xml.dom.NodeFilter', 'xml.dom.domreg',
|
||||
'xml.dom.expatbuilder', 'xml.dom.minicompat', 'xml.dom.minidom', 'xml.dom.pulldom', 'xml.dom.xmlbuilder', 'xmlrpc.server'],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=['gluon'],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='web2py_no_console',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False , icon='extras\\icons\\web2py.ico')
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='web2py_no_console')
|
||||
Reference in New Issue
Block a user