mirror of https://github.com/borgbackup/borg.git
147 lines
5.1 KiB
Python
147 lines
5.1 KiB
Python
import shutil
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from modulefinder import ModuleFinder
|
|
import zipfile
|
|
|
|
# Creates standalone Windows executable
|
|
# First build by following instructions from installation.rst
|
|
|
|
builddir = 'win32exe'
|
|
|
|
pythonversion = str(sys.version_info[0]) + '.' + str(sys.version_info[1])
|
|
|
|
if os.path.exists(builddir):
|
|
shutil.rmtree(builddir)
|
|
os.mkdir(builddir)
|
|
os.mkdir(builddir + '/bin')
|
|
library = zipfile.PyZipFile(os.path.join(builddir, 'library.zip'), mode='w')
|
|
|
|
print('Compiling wrapper')
|
|
|
|
gccpath = '' # check for compiler, path needed later
|
|
for p in os.environ['PATH'].split(';'):
|
|
if os.path.exists(os.path.join(p, 'g++.exe')):
|
|
gccpath = p
|
|
break
|
|
if gccpath == '':
|
|
print('g++ not found.')
|
|
exit(1)
|
|
|
|
source = open('wrapper.c', 'w')
|
|
source.write(
|
|
"""
|
|
#include <python""" + pythonversion + """m/python.h>
|
|
#include <windows.h>
|
|
#include <wchar.h>
|
|
#include <string>
|
|
#include "Shlwapi.h"
|
|
|
|
int wmain(int argc , wchar_t *argv[] )
|
|
{
|
|
wchar_t path[MAX_PATH];
|
|
GetModuleFileNameW(NULL, path, MAX_PATH);
|
|
PathRemoveFileSpecW(path);
|
|
std::wstring selfpath(path);
|
|
std::wstring libpath = selfpath + L"/library.zip;" + selfpath + L"/bin";
|
|
SetDllDirectoryW(path);
|
|
|
|
Py_SetPath(libpath.c_str());
|
|
Py_SetProgramName(argv[0]);
|
|
Py_Initialize();
|
|
PySys_SetArgv(argc, argv);
|
|
|
|
PyImport_ImportModule("encodings.idna");
|
|
PyRun_SimpleString("from runpy import run_module\\n"
|
|
"run_module('borg')");
|
|
|
|
Py_Finalize();
|
|
return 0;
|
|
}
|
|
""")
|
|
source.close()
|
|
subprocess.check_call('g++ wrapper.c -lpython' + pythonversion + 'm -lshlwapi -municode -o ' + builddir + '/borg.exe')
|
|
os.remove('wrapper.c')
|
|
|
|
print('Searching modules')
|
|
|
|
modulepath = os.path.abspath(os.path.join(gccpath, '../lib/python' + pythonversion + '/'))
|
|
|
|
# Bundle all encodings - In theory user may use any encoding in command prompt
|
|
for file in os.listdir(os.path.join(modulepath, 'encodings')):
|
|
if os.path.isfile(os.path.join(modulepath, 'encodings', file)):
|
|
library.write(os.path.join(modulepath, 'encodings', file), os.path.join('encodings', file))
|
|
|
|
finder = ModuleFinder()
|
|
finder.run_script('src/borg/__main__.py')
|
|
|
|
# For some reason modulefinder does not find these, add them manually
|
|
extramodules = [os.path.join(modulepath, 'site.py'), os.path.join(modulepath, 'encodings/idna.py'),
|
|
os.path.join(modulepath, 'stringprep.py'), os.path.join(modulepath, 'ctypes/wintypes.py'),
|
|
os.path.join(modulepath, 'lib-dynload/_sysconfigdata_m_win32_.py')]
|
|
|
|
for module in extramodules:
|
|
finder.run_script(module)
|
|
|
|
print('Copying files')
|
|
|
|
|
|
def finddlls(exe):
|
|
re = []
|
|
output = subprocess.check_output(['ntldd', '-R', exe])
|
|
for line in output.decode('utf-8').split('\n'):
|
|
if 'not found' in line:
|
|
continue
|
|
if 'windows' in line.lower():
|
|
continue
|
|
words = line.split()
|
|
if len(words) < 3:
|
|
if len(words) == 2:
|
|
re.append(words[0])
|
|
continue
|
|
dll = words[2]
|
|
re.append(dll)
|
|
return re
|
|
|
|
|
|
items = finder.modules.items()
|
|
for name, mod in items:
|
|
file = mod.__file__
|
|
if file is None:
|
|
continue
|
|
lib = file.find('lib')
|
|
if lib == -1:
|
|
# Part of the borg package
|
|
relpath = os.path.relpath(file)[4:]
|
|
os.makedirs(os.path.join(builddir, 'bin', os.path.split(relpath)[0]), exist_ok=True)
|
|
shutil.copyfile(file, os.path.join(builddir, 'bin', relpath))
|
|
else:
|
|
relativepath = file[file.find('lib')+len('lib/python' + pythonversion + '/'):]
|
|
if 'encodings' in file:
|
|
continue
|
|
if relativepath not in library.namelist():
|
|
if relativepath.startswith('site-packages'):
|
|
relativepath = relativepath[len('site-packages/'):]
|
|
library.write(file, relativepath)
|
|
if file.endswith(('dll', 'DLL')):
|
|
shutil.copyfile(file, os.path.join(builddir, 'bin', os.path.split(file)[1]))
|
|
for dll in finddlls(file):
|
|
if builddir not in dll:
|
|
shutil.copyfile(dll, os.path.join(builddir, os.path.split(dll)[1]))
|
|
for dll in finddlls(os.path.join(builddir, "borg.exe")):
|
|
if builddir not in dll:
|
|
shutil.copyfile(dll, os.path.join(builddir, os.path.split(dll)[1]))
|
|
|
|
shutil.copyfile(os.path.join('src', 'borg', '__main__.py'), os.path.join(builddir, 'bin', 'borg', '__main__.py'))
|
|
library.write(os.path.join(modulepath, 'lib-dynload/_sysconfigdata_m_win32_.py'), '_sysconfigdata_m_win32_.py')
|
|
library.write(os.path.join(modulepath, 'ctypes/wintypes.py'), 'ctypes/wintypes.py')
|
|
|
|
for extmodule in ['src/borg/chunker-cpython-' + str(sys.version_info[0]) + str(sys.version_info[1]) + 'm.dll',
|
|
'src/borg/compress-cpython-' + str(sys.version_info[0]) + str(sys.version_info[1]) + 'm.dll',
|
|
'src/borg/item-cpython-' + str(sys.version_info[0]) + str(sys.version_info[1]) + 'm.dll',
|
|
'src/borg/hashindex-cpython-' + str(sys.version_info[0]) + str(sys.version_info[1]) + 'm.dll']:
|
|
for dll in finddlls(extmodule):
|
|
if builddir not in dll:
|
|
shutil.copyfile(dll, os.path.join(builddir, os.path.split(dll)[1]))
|