forked from e3krisztian/bead
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.py
executable file
·134 lines (99 loc) · 3.26 KB
/
build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
# coding: utf-8
import os
import stat
from subprocess import run, PIPE
from glob import glob
import shutil
from zipfile import ZipFile, ZIP_DEFLATED
import contextlib
BUILD = 'executables'
PKGS = BUILD + '/pkgs'
SRC = BUILD + '/src'
TOOL_PYZ = BUILD + '/bead.pyz'
UNIX_TOOL = BUILD + '/bead'
WIN_TOOL = BUILD + '/bead.cmd'
def mkdir(dir):
if not os.path.isdir(dir):
print(f'mkdir {dir}')
os.makedirs(dir)
def pip(*args):
print(f'pip {" ".join(args)}')
return run(('pip',) + args, check=True)
def pip_download_source(*args):
return pip('download', '--no-binary', ':all:', *args)
def rmtree(dir):
print(f'rm -rf {dir}')
shutil.rmtree(dir, ignore_errors=True)
def make_executable(file):
print(f'chmod +x {file}')
st = os.stat(file)
os.chmod(file, st.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
@contextlib.contextmanager
def notification(msg, long_output=False):
if long_output:
print(msg + ':')
print()
print('-' * 32)
else:
print(' * ' + msg)
try:
yield
finally:
if long_output:
print('-' * 32)
print()
def further_output(msg):
return notification(msg, long_output=True)
progress = notification
# start with no build directory
with further_output('Clean up'):
rmtree(BUILD)
git_ls_files = run(['git', 'ls-files'], stdout=PIPE, check=True).stdout.decode('utf-8')
PY_SOURCES = [
line
for line in git_ls_files.splitlines()
if line.endswith('.py')
]
with further_output('Copying over our sources'):
PY_DIRS = sorted({os.path.dirname(file) for file in PY_SOURCES})
for dir in PY_DIRS:
mkdir(os.path.join(SRC, dir))
for file in PY_SOURCES:
shutil.copy(file, os.path.join(SRC, file))
with further_output('Downloading dependencies'):
mkdir(PKGS)
pip_download_source('--dest', PKGS, '--exists-action', 'w', '-r', 'requirements.txt')
with further_output('Unpacking packages'):
mkdir(SRC)
for package in glob(PKGS + '/*'):
pip('install', '--target', SRC, '--no-compile', '--no-deps', package)
# # Technically we do not need these files,
# # however licensing forces us to copy and keep them :(
# for dir in glob(SRC + '/*.egg-info'):
# rmtree(dir)
with progress(f'Creating .pyz zip archive from the sources ({TOOL_PYZ})'):
with ZipFile(TOOL_PYZ, mode='w', compression=ZIP_DEFLATED) as zip:
for realroot, dirs, files in os.walk(SRC):
ziproot = os.path.relpath(realroot, SRC)
for file_name in files:
zip.write(
os.path.join(realroot, file_name),
os.path.join(ziproot, file_name))
def make_tool(tool_file_name, runner):
with open(tool_file_name, 'wb') as f:
f.write(runner)
with open(TOOL_PYZ, 'rb') as pyz:
f.write(pyz.read())
with progress(f'Creating unix tool ({UNIX_TOOL})'):
UNIX_RUNNER = b'#!/usr/bin/env python3\n'
make_tool(UNIX_TOOL, UNIX_RUNNER)
make_executable(UNIX_TOOL)
with progress(f'Creating windows tool ({WIN_TOOL})'):
WINDOWS_RUNNER = b'\r\n'.join((
b'@echo off',
b'python3.exe "%~f0" %*',
b'exit /b %errorlevel%',
b''))
make_tool(WIN_TOOL, WINDOWS_RUNNER)
print('Done.')