##// END OF EJS Templates
packaging: extract virtualenv and py2exe to build directory...
Gregory Szorc -
r42078:d4bf73ea default
parent child Browse files
Show More
@@ -1,169 +1,171 b''
1 # inno.py - Inno Setup functionality.
1 # inno.py - Inno Setup functionality.
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import os
10 import os
11 import pathlib
11 import pathlib
12 import shutil
12 import shutil
13 import subprocess
13 import subprocess
14 import tempfile
14 import tempfile
15
15
16 from .downloads import (
16 from .downloads import (
17 download_entry,
17 download_entry,
18 )
18 )
19 from .util import (
19 from .util import (
20 extract_tar_to_directory,
20 extract_tar_to_directory,
21 extract_zip_to_directory,
21 extract_zip_to_directory,
22 find_vc_runtime_files,
22 find_vc_runtime_files,
23 )
23 )
24
24
25
25
26 PRINT_PYTHON_INFO = '''
26 PRINT_PYTHON_INFO = '''
27 import platform, sys; print("%s:%d" % (platform.architecture()[0], sys.version_info[0]))
27 import platform, sys; print("%s:%d" % (platform.architecture()[0], sys.version_info[0]))
28 '''.strip()
28 '''.strip()
29
29
30
30
31 def build(source_dir: pathlib.Path, build_dir: pathlib.Path,
31 def build(source_dir: pathlib.Path, build_dir: pathlib.Path,
32 python_exe: pathlib.Path, iscc_exe: pathlib.Path,
32 python_exe: pathlib.Path, iscc_exe: pathlib.Path,
33 version=None):
33 version=None):
34 """Build the Inno installer.
34 """Build the Inno installer.
35
35
36 Build files will be placed in ``build_dir``.
36 Build files will be placed in ``build_dir``.
37
37
38 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
38 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
39 for finding the Python 2.7 toolchain. So, we require the environment
39 for finding the Python 2.7 toolchain. So, we require the environment
40 to already be configured with an active toolchain.
40 to already be configured with an active toolchain.
41 """
41 """
42 if not iscc_exe.exists():
42 if not iscc_exe.exists():
43 raise Exception('%s does not exist' % iscc_exe)
43 raise Exception('%s does not exist' % iscc_exe)
44
44
45 if 'VCINSTALLDIR' not in os.environ:
45 if 'VCINSTALLDIR' not in os.environ:
46 raise Exception('not running from a Visual C++ build environment; '
46 raise Exception('not running from a Visual C++ build environment; '
47 'execute the "Visual C++ <version> Command Prompt" '
47 'execute the "Visual C++ <version> Command Prompt" '
48 'application shortcut or a vcsvarsall.bat file')
48 'application shortcut or a vcsvarsall.bat file')
49
49
50 # Identity x86/x64 and validate the environment matches the Python
50 # Identity x86/x64 and validate the environment matches the Python
51 # architecture.
51 # architecture.
52 vc_x64 = r'\x64' in os.environ['LIB']
52 vc_x64 = r'\x64' in os.environ['LIB']
53
53
54 res = subprocess.run(
54 res = subprocess.run(
55 [str(python_exe), '-c', PRINT_PYTHON_INFO],
55 [str(python_exe), '-c', PRINT_PYTHON_INFO],
56 capture_output=True, check=True)
56 capture_output=True, check=True)
57
57
58 py_arch, py_version = res.stdout.decode('utf-8').split(':')
58 py_arch, py_version = res.stdout.decode('utf-8').split(':')
59 py_version = int(py_version)
59 py_version = int(py_version)
60
60
61 if vc_x64:
61 if vc_x64:
62 if py_arch != '64bit':
62 if py_arch != '64bit':
63 raise Exception('architecture mismatch: Visual C++ environment '
63 raise Exception('architecture mismatch: Visual C++ environment '
64 'is configured for 64-bit but Python is 32-bit')
64 'is configured for 64-bit but Python is 32-bit')
65 else:
65 else:
66 if py_arch != '32bit':
66 if py_arch != '32bit':
67 raise Exception('architecture mismatch: Visual C++ environment '
67 raise Exception('architecture mismatch: Visual C++ environment '
68 'is configured for 32-bit but Python is 64-bit')
68 'is configured for 32-bit but Python is 64-bit')
69
69
70 if py_version != 2:
70 if py_version != 2:
71 raise Exception('Only Python 2 is currently supported')
71 raise Exception('Only Python 2 is currently supported')
72
72
73 build_dir.mkdir(exist_ok=True)
73 build_dir.mkdir(exist_ok=True)
74
74
75 gettext_pkg, gettext_entry = download_entry('gettext', build_dir)
75 gettext_pkg, gettext_entry = download_entry('gettext', build_dir)
76 gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0]
76 gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0]
77 virtualenv_pkg, virtualenv_entry = download_entry('virtualenv', build_dir)
77 virtualenv_pkg, virtualenv_entry = download_entry('virtualenv', build_dir)
78 py2exe_pkg, py2exe_entry = download_entry('py2exe', build_dir)
78 py2exe_pkg, py2exe_entry = download_entry('py2exe', build_dir)
79
79
80 venv_path = build_dir / ('venv-inno-%s' % ('x64' if vc_x64 else 'x86'))
80 venv_path = build_dir / ('venv-inno-%s' % ('x64' if vc_x64 else 'x86'))
81
81
82 gettext_root = build_dir / (
82 gettext_root = build_dir / (
83 'gettext-win-%s' % gettext_entry['version'])
83 'gettext-win-%s' % gettext_entry['version'])
84
84
85 if not gettext_root.exists():
85 if not gettext_root.exists():
86 extract_zip_to_directory(gettext_pkg, gettext_root)
86 extract_zip_to_directory(gettext_pkg, gettext_root)
87 extract_zip_to_directory(gettext_dep_pkg, gettext_root)
87 extract_zip_to_directory(gettext_dep_pkg, gettext_root)
88
88
89 # This assumes Python 2. We don't need virtualenv on Python 3.
90 virtualenv_src_path = build_dir / (
91 'virtualenv-%s' % virtualenv_entry['version'])
92 virtualenv_py = virtualenv_src_path / 'virtualenv.py'
93
94 if not virtualenv_src_path.exists():
95 extract_tar_to_directory(virtualenv_pkg, build_dir)
96
97 py2exe_source_path = build_dir / ('py2exe-%s' % py2exe_entry['version'])
98
99 if not py2exe_source_path.exists():
100 extract_zip_to_directory(py2exe_pkg, build_dir)
101
89 with tempfile.TemporaryDirectory() as td:
102 with tempfile.TemporaryDirectory() as td:
90 td = pathlib.Path(td)
103 td = pathlib.Path(td)
91
104
92 # This assumes Python 2.
93 extract_tar_to_directory(virtualenv_pkg, td)
94 extract_zip_to_directory(py2exe_pkg, td)
95
96 virtualenv_src_path = td / ('virtualenv-%s' %
97 virtualenv_entry['version'])
98 py2exe_source_path = td / ('py2exe-%s' %
99 py2exe_entry['version'])
100
101 virtualenv_py = virtualenv_src_path / 'virtualenv.py'
102
103 if not venv_path.exists():
105 if not venv_path.exists():
104 print('creating virtualenv with dependencies')
106 print('creating virtualenv with dependencies')
105 subprocess.run(
107 subprocess.run(
106 [str(python_exe), str(virtualenv_py), str(venv_path)],
108 [str(python_exe), str(virtualenv_py), str(venv_path)],
107 check=True)
109 check=True)
108
110
109 venv_python = venv_path / 'Scripts' / 'python.exe'
111 venv_python = venv_path / 'Scripts' / 'python.exe'
110 venv_pip = venv_path / 'Scripts' / 'pip.exe'
112 venv_pip = venv_path / 'Scripts' / 'pip.exe'
111
113
112 requirements_txt = (source_dir / 'contrib' / 'packaging' /
114 requirements_txt = (source_dir / 'contrib' / 'packaging' /
113 'inno' / 'requirements.txt')
115 'inno' / 'requirements.txt')
114 subprocess.run([str(venv_pip), 'install', '-r', str(requirements_txt)],
116 subprocess.run([str(venv_pip), 'install', '-r', str(requirements_txt)],
115 check=True)
117 check=True)
116
118
117 # Force distutils to use VC++ settings from environment, which was
119 # Force distutils to use VC++ settings from environment, which was
118 # validated above.
120 # validated above.
119 env = dict(os.environ)
121 env = dict(os.environ)
120 env['DISTUTILS_USE_SDK'] = '1'
122 env['DISTUTILS_USE_SDK'] = '1'
121 env['MSSdk'] = '1'
123 env['MSSdk'] = '1'
122
124
123 py2exe_py_path = venv_path / 'Lib' / 'site-packages' / 'py2exe'
125 py2exe_py_path = venv_path / 'Lib' / 'site-packages' / 'py2exe'
124 if not py2exe_py_path.exists():
126 if not py2exe_py_path.exists():
125 print('building py2exe')
127 print('building py2exe')
126 subprocess.run([str(venv_python), 'setup.py', 'install'],
128 subprocess.run([str(venv_python), 'setup.py', 'install'],
127 cwd=py2exe_source_path,
129 cwd=py2exe_source_path,
128 env=env,
130 env=env,
129 check=True)
131 check=True)
130
132
131 # Register location of msgfmt and other binaries.
133 # Register location of msgfmt and other binaries.
132 env['PATH'] = '%s%s%s' % (
134 env['PATH'] = '%s%s%s' % (
133 env['PATH'], os.pathsep, str(gettext_root / 'bin'))
135 env['PATH'], os.pathsep, str(gettext_root / 'bin'))
134
136
135 print('building Mercurial')
137 print('building Mercurial')
136 subprocess.run(
138 subprocess.run(
137 [str(venv_python), 'setup.py',
139 [str(venv_python), 'setup.py',
138 'py2exe', '-b', '3' if vc_x64 else '2',
140 'py2exe', '-b', '3' if vc_x64 else '2',
139 'build_doc', '--html'],
141 'build_doc', '--html'],
140 cwd=str(source_dir),
142 cwd=str(source_dir),
141 env=env,
143 env=env,
142 check=True)
144 check=True)
143
145
144 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
146 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
145 for f in find_vc_runtime_files(vc_x64):
147 for f in find_vc_runtime_files(vc_x64):
146 if f.name.endswith('.manifest'):
148 if f.name.endswith('.manifest'):
147 basename = 'Microsoft.VC90.CRT.manifest'
149 basename = 'Microsoft.VC90.CRT.manifest'
148 else:
150 else:
149 basename = f.name
151 basename = f.name
150
152
151 dest_path = source_dir / 'dist' / basename
153 dest_path = source_dir / 'dist' / basename
152
154
153 print('copying %s to %s' % (f, dest_path))
155 print('copying %s to %s' % (f, dest_path))
154 shutil.copyfile(f, dest_path)
156 shutil.copyfile(f, dest_path)
155
157
156 print('creating installer')
158 print('creating installer')
157
159
158 args = [str(iscc_exe)]
160 args = [str(iscc_exe)]
159
161
160 if vc_x64:
162 if vc_x64:
161 args.append('/dARCH=x64')
163 args.append('/dARCH=x64')
162
164
163 if version:
165 if version:
164 args.append('/dVERSION=%s' % version)
166 args.append('/dVERSION=%s' % version)
165
167
166 args.append('/Odist')
168 args.append('/Odist')
167 args.append('contrib/packaging/inno/mercurial.iss')
169 args.append('contrib/packaging/inno/mercurial.iss')
168
170
169 subprocess.run(args, cwd=str(source_dir), check=True)
171 subprocess.run(args, cwd=str(source_dir), check=True)
General Comments 0
You need to be logged in to leave comments. Login now