diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/gladtex/create_windows_distributions.py |
Initial commit
Diffstat (limited to 'support/gladtex/create_windows_distributions.py')
-rw-r--r-- | support/gladtex/create_windows_distributions.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/support/gladtex/create_windows_distributions.py b/support/gladtex/create_windows_distributions.py new file mode 100644 index 0000000000..3c7ca2c6cf --- /dev/null +++ b/support/gladtex/create_windows_distributions.py @@ -0,0 +1,140 @@ +""" +This file builds windows distributions, zip files with GladTeX and all other +files.""" +import os +import shutil +import stat +import sys +import zipfile +import gleetex + +def exec_setup_py(arg_string): + """Execute `python setup.py` as a subprocess. Use Wine, if necessary.""" + ret = None + if sys.platform.startswith('win'): + ret = os.system('python setup.py ' + arg_string) + else: + if not shutil.which('wine'): + print("Error: Wine is not installed, aborting…") + sys.exit(5) + ret = os.system('wine python setup.py ' + arg_string) + if ret: + if sys.platform.startswith('win'): + print("Aborting at command `python setup.py %s`." % arg_string) + else: + print("Aborting at command `wine python setup.py %s`." % arg_string) + sys.exit(7) + +def get_python_version(): + """Return the python version as a string.""" + import re, subprocess + args = ['python', '--version'] + if not sys.platform.startswith('win'): + args = ['wine'] + args + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + stdout = proc.communicate()[0].decode(sys.getdefaultencoding()) + if proc.wait(): + raise TypeError("Abnormal subprocess termination while querying python version.") + return re.search(r'.*?(\d+\.\d+\.\d+)', stdout).groups()[0] + +def get_executable_name(label): + """Construct the name of an executable""" + return 'gladtex-win64-%s-py_%s-%s.zip' % (gleetex.VERSION, get_python_version(), + label) + +def bundle_files(src, output_name): + """Bundle the compiled binary files with README, ChangeLog and COPYING.""" + if os.path.exists(output_name): + shutil.rmtree(output_name) + os.rename(src, output_name) + # add README.first + with open(os.path.join(output_name, 'README.first.txt'), 'w') as f: + f.write('GladTeX for Windows\r\n===================\r\n\r\n') + f.write('This program has been compiled with python 3.4.4. If you want to embedd it in binary form with your binary python application, the version numbers HAVE TO match.\r\n') + f.write('\r\nFor more information, see the file README.md or http://humenda.github.io/GladTeX\r\n') + + # copy README and other files + for file in ['README.md', 'COPYING', 'ChangeLog']: + dest = os.path.join(output_name, file) + # check whether file ending exists + if not '.' in dest[-5:]: + dest += '.txt' + shutil.copy(file, dest) + + files = [os.path.join(root, file) + for root, _, files in os.walk(output_name) for file in files] + with zipfile.ZipFile(output_name + '.zip', 'w', zipfile.ZIP_DEFLATED) as z: + for file in files: + z.write(file) + shutil.rmtree(output_name) + +class TemporaryBuildDirectory(): + """Context handler to guard the build process. + Upon entering the context, the source is copied to a temporary directory and + the program changes to this directory. After all build actions have been + done, the output file is copied back to the original directory, the program + resets the current working directory and deletes the temporary directory.""" + def __init__(self, output_file_name): + self.orig_cwd = os.getcwd() + self.tmpdir = None + self.output_file_name = output_file_name + + def __enter__(self): + self.tmpdir = self.get_temp_directory() + shutil.copytree(os.getcwd(), self.tmpdir) + os.chdir(self.tmpdir) + return self + + def __exit__(self, _a, _b, _c): + os.chdir(self.orig_cwd) + shutil.copy(os.path.join(self.tmpdir, self.output_file_name), + self.output_file_name) + shutil.rmtree(self.tmpdir, onerror=self.__onerror) + + def get_temp_directory(self): + """Find a temporary directory to work in. The checks are done to find a + directory which does not reside within the user's path, because py2exe + includes absolute paths for python scripts (in their tracebacks). It is not + desirable to show the whole world the directory layout of the computer where + the source code was built on.""" + tmp_base = None + if os.path.exists('/tmp'): + tmp_base = '/tmp' + elif os.path.exists('\\temp'): + tmp_base = '\\temp' + elif os.path.exists('\\windows\\temp'): + tmp_base = '\\windows\\temp' + else: + import tempfile + tmp_base = tempfile.gettempdir() + tmpdir = os.path.join(tmp_base, 'gladtex.build') + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir, onerror=self.__onerror) + return tmpdir + + def __onerror(self, func, path, exc_info): + """ + Error handler for ``shutil.rmtree``. + If the error is due to an access error (read only file) it attempts to + add write permission and then retries. If the error is for another reason it re-raises the error. + Usage : ``shutil.rmtree(path, onerror=onerror)``.""" + if not os.access(path, os.W_OK): + # Is the error an access error ? + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise exc_info + + +if __name__ == '__main__': + with TemporaryBuildDirectory(get_executable_name('embeddable')) as tb: + # build embeddable release, where all files are separate DLL's; if somebody + # distributes a python app, these DLL files can be shared + exec_setup_py('py2exe -c -O 2 -i gleetex --bundle-files 3') + bundle_files('dist', os.path.splitext(tb.output_file_name)[0]) + + # create a stand-alone version of GladTeX + with TemporaryBuildDirectory(get_executable_name('standalone')) as tb: + exec_setup_py('py2exe -i gleetex -c -O 2 --bundle-files 1') + bundle_files('dist', os.path.splitext(tb.output_file_name)[0]) + |