##// END OF EJS Templates
pyoxidizer: re-install PYTHONPATH behavior...
marmoute -
r48658:b962a913 stable
parent child Browse files
Show More
@@ -1,295 +1,303 b''
1 # The following variables can be passed in as parameters:
1 # The following variables can be passed in as parameters:
2 #
2 #
3 # VERSION
3 # VERSION
4 # Version string of program being produced.
4 # Version string of program being produced.
5 #
5 #
6 # MSI_NAME
6 # MSI_NAME
7 # Root name of MSI installer.
7 # Root name of MSI installer.
8 #
8 #
9 # EXTRA_MSI_FEATURES
9 # EXTRA_MSI_FEATURES
10 # ; delimited string of extra features to advertise in the built MSA.
10 # ; delimited string of extra features to advertise in the built MSA.
11 #
11 #
12 # SIGNING_PFX_PATH
12 # SIGNING_PFX_PATH
13 # Path to code signing certificate to use.
13 # Path to code signing certificate to use.
14 #
14 #
15 # SIGNING_PFX_PASSWORD
15 # SIGNING_PFX_PASSWORD
16 # Password to code signing PFX file defined by SIGNING_PFX_PATH.
16 # Password to code signing PFX file defined by SIGNING_PFX_PATH.
17 #
17 #
18 # SIGNING_SUBJECT_NAME
18 # SIGNING_SUBJECT_NAME
19 # String fragment in code signing certificate subject name used to find
19 # String fragment in code signing certificate subject name used to find
20 # code signing certificate in Windows certificate store.
20 # code signing certificate in Windows certificate store.
21 #
21 #
22 # TIME_STAMP_SERVER_URL
22 # TIME_STAMP_SERVER_URL
23 # URL of time-stamp token authority (RFC 3161) servers to stamp code signatures.
23 # URL of time-stamp token authority (RFC 3161) servers to stamp code signatures.
24
24
25 ROOT = CWD + "/../.."
25 ROOT = CWD + "/../.."
26
26
27 VERSION = VARS.get("VERSION", "5.8")
27 VERSION = VARS.get("VERSION", "5.8")
28 MSI_NAME = VARS.get("MSI_NAME", "mercurial")
28 MSI_NAME = VARS.get("MSI_NAME", "mercurial")
29 EXTRA_MSI_FEATURES = VARS.get("EXTRA_MSI_FEATURES")
29 EXTRA_MSI_FEATURES = VARS.get("EXTRA_MSI_FEATURES")
30 SIGNING_PFX_PATH = VARS.get("SIGNING_PFX_PATH")
30 SIGNING_PFX_PATH = VARS.get("SIGNING_PFX_PATH")
31 SIGNING_PFX_PASSWORD = VARS.get("SIGNING_PFX_PASSWORD", "")
31 SIGNING_PFX_PASSWORD = VARS.get("SIGNING_PFX_PASSWORD", "")
32 SIGNING_SUBJECT_NAME = VARS.get("SIGNING_SUBJECT_NAME")
32 SIGNING_SUBJECT_NAME = VARS.get("SIGNING_SUBJECT_NAME")
33 TIME_STAMP_SERVER_URL = VARS.get("TIME_STAMP_SERVER_URL", "http://timestamp.digicert.com")
33 TIME_STAMP_SERVER_URL = VARS.get("TIME_STAMP_SERVER_URL", "http://timestamp.digicert.com")
34
34
35 IS_WINDOWS = "windows" in BUILD_TARGET_TRIPLE
35 IS_WINDOWS = "windows" in BUILD_TARGET_TRIPLE
36
36
37 # Code to run in Python interpreter.
37 # Code to run in Python interpreter.
38 RUN_CODE = """
38 RUN_CODE = """
39 import os
40 import sys
41 extra_path = os.environ.get('PYTHONPATH')
42 if extra_path is not None:
43 # extensions and hooks expect a working python environment
44 # We do not prepend the values because the Mercurial library wants to be in
45 # the front of the sys.path to avoid picking up other installations.
46 sys.path.extend(extra_path.split(os.pathsep))
39 import hgdemandimport;
47 import hgdemandimport;
40 hgdemandimport.enable();
48 hgdemandimport.enable();
41 from mercurial import dispatch;
49 from mercurial import dispatch;
42 dispatch.run();
50 dispatch.run();
43 """
51 """
44
52
45 set_build_path(ROOT + "/build/pyoxidizer")
53 set_build_path(ROOT + "/build/pyoxidizer")
46
54
47 def make_distribution():
55 def make_distribution():
48 return default_python_distribution(python_version = "3.9")
56 return default_python_distribution(python_version = "3.9")
49
57
50 def resource_callback(policy, resource):
58 def resource_callback(policy, resource):
51 if not IS_WINDOWS:
59 if not IS_WINDOWS:
52 resource.add_location = "in-memory"
60 resource.add_location = "in-memory"
53 return
61 return
54
62
55 # We use a custom resource routing policy to influence where things are loaded
63 # We use a custom resource routing policy to influence where things are loaded
56 # from.
64 # from.
57 #
65 #
58 # For Python modules and resources, we load from memory if they are in
66 # For Python modules and resources, we load from memory if they are in
59 # the standard library and from the filesystem if not. This is because
67 # the standard library and from the filesystem if not. This is because
60 # parts of Mercurial and some 3rd party packages aren't yet compatible
68 # parts of Mercurial and some 3rd party packages aren't yet compatible
61 # with memory loading.
69 # with memory loading.
62 #
70 #
63 # For Python extension modules, we load from the filesystem because
71 # For Python extension modules, we load from the filesystem because
64 # this yields greatest compatibility.
72 # this yields greatest compatibility.
65 if type(resource) in ("PythonModuleSource", "PythonPackageResource", "PythonPackageDistributionResource"):
73 if type(resource) in ("PythonModuleSource", "PythonPackageResource", "PythonPackageDistributionResource"):
66 if resource.is_stdlib:
74 if resource.is_stdlib:
67 resource.add_location = "in-memory"
75 resource.add_location = "in-memory"
68 else:
76 else:
69 resource.add_location = "filesystem-relative:lib"
77 resource.add_location = "filesystem-relative:lib"
70
78
71 elif type(resource) == "PythonExtensionModule":
79 elif type(resource) == "PythonExtensionModule":
72 resource.add_location = "filesystem-relative:lib"
80 resource.add_location = "filesystem-relative:lib"
73
81
74 def make_exe(dist):
82 def make_exe(dist):
75 """Builds a Rust-wrapped Mercurial binary."""
83 """Builds a Rust-wrapped Mercurial binary."""
76 packaging_policy = dist.make_python_packaging_policy()
84 packaging_policy = dist.make_python_packaging_policy()
77
85
78 # Extension may depend on any Python functionality. Include all
86 # Extension may depend on any Python functionality. Include all
79 # extensions.
87 # extensions.
80 packaging_policy.extension_module_filter = "all"
88 packaging_policy.extension_module_filter = "all"
81 packaging_policy.resources_location = "in-memory"
89 packaging_policy.resources_location = "in-memory"
82 if IS_WINDOWS:
90 if IS_WINDOWS:
83 packaging_policy.resources_location_fallback = "filesystem-relative:lib"
91 packaging_policy.resources_location_fallback = "filesystem-relative:lib"
84 packaging_policy.register_resource_callback(resource_callback)
92 packaging_policy.register_resource_callback(resource_callback)
85
93
86 config = dist.make_python_interpreter_config()
94 config = dist.make_python_interpreter_config()
87 config.allocator_backend = "default"
95 config.allocator_backend = "default"
88 config.run_command = RUN_CODE
96 config.run_command = RUN_CODE
89
97
90 # We want to let the user load extensions from the file system
98 # We want to let the user load extensions from the file system
91 config.filesystem_importer = True
99 config.filesystem_importer = True
92
100
93 # We need this to make resourceutil happy, since it looks for sys.frozen.
101 # We need this to make resourceutil happy, since it looks for sys.frozen.
94 config.sys_frozen = True
102 config.sys_frozen = True
95 config.legacy_windows_stdio = True
103 config.legacy_windows_stdio = True
96
104
97 exe = dist.to_python_executable(
105 exe = dist.to_python_executable(
98 name = "hg",
106 name = "hg",
99 packaging_policy = packaging_policy,
107 packaging_policy = packaging_policy,
100 config = config,
108 config = config,
101 )
109 )
102
110
103 # Add Mercurial to resources.
111 # Add Mercurial to resources.
104 exe.add_python_resources(exe.pip_install(["--verbose", ROOT]))
112 exe.add_python_resources(exe.pip_install(["--verbose", ROOT]))
105
113
106 # On Windows, we install extra packages for convenience.
114 # On Windows, we install extra packages for convenience.
107 if IS_WINDOWS:
115 if IS_WINDOWS:
108 exe.add_python_resources(
116 exe.add_python_resources(
109 exe.pip_install(["-r", ROOT + "/contrib/packaging/requirements-windows-py3.txt"]),
117 exe.pip_install(["-r", ROOT + "/contrib/packaging/requirements-windows-py3.txt"]),
110 )
118 )
111 extra_packages = VARS.get("extra_py_packages", "")
119 extra_packages = VARS.get("extra_py_packages", "")
112 if extra_packages:
120 if extra_packages:
113 for extra in extra_packages.split(","):
121 for extra in extra_packages.split(","):
114 extra_src, pkgs = extra.split("=")
122 extra_src, pkgs = extra.split("=")
115 pkgs = pkgs.split(":")
123 pkgs = pkgs.split(":")
116 exe.add_python_resources(exe.read_package_root(extra_src, pkgs))
124 exe.add_python_resources(exe.read_package_root(extra_src, pkgs))
117
125
118 return exe
126 return exe
119
127
120 def make_manifest(dist, exe):
128 def make_manifest(dist, exe):
121 m = FileManifest()
129 m = FileManifest()
122 m.add_python_resource(".", exe)
130 m.add_python_resource(".", exe)
123
131
124 return m
132 return m
125
133
126
134
127 # This adjusts the InstallManifest produced from exe generation to provide
135 # This adjusts the InstallManifest produced from exe generation to provide
128 # additional files found in a Windows install layout.
136 # additional files found in a Windows install layout.
129 def make_windows_install_layout(manifest):
137 def make_windows_install_layout(manifest):
130 # Copy various files to new install locations. This can go away once
138 # Copy various files to new install locations. This can go away once
131 # we're using the importlib resource reader.
139 # we're using the importlib resource reader.
132 RECURSIVE_COPIES = {
140 RECURSIVE_COPIES = {
133 "lib/mercurial/locale/": "locale/",
141 "lib/mercurial/locale/": "locale/",
134 "lib/mercurial/templates/": "templates/",
142 "lib/mercurial/templates/": "templates/",
135 }
143 }
136 for (search, replace) in RECURSIVE_COPIES.items():
144 for (search, replace) in RECURSIVE_COPIES.items():
137 for path in manifest.paths():
145 for path in manifest.paths():
138 if path.startswith(search):
146 if path.startswith(search):
139 new_path = path.replace(search, replace)
147 new_path = path.replace(search, replace)
140 print("copy %s to %s" % (path, new_path))
148 print("copy %s to %s" % (path, new_path))
141 file = manifest.get_file(path)
149 file = manifest.get_file(path)
142 manifest.add_file(file, path = new_path)
150 manifest.add_file(file, path = new_path)
143
151
144 # Similar to above, but with filename pattern matching.
152 # Similar to above, but with filename pattern matching.
145 # lib/mercurial/helptext/**/*.txt -> helptext/
153 # lib/mercurial/helptext/**/*.txt -> helptext/
146 # lib/mercurial/defaultrc/*.rc -> defaultrc/
154 # lib/mercurial/defaultrc/*.rc -> defaultrc/
147 for path in manifest.paths():
155 for path in manifest.paths():
148 if path.startswith("lib/mercurial/helptext/") and path.endswith(".txt"):
156 if path.startswith("lib/mercurial/helptext/") and path.endswith(".txt"):
149 new_path = path[len("lib/mercurial/"):]
157 new_path = path[len("lib/mercurial/"):]
150 elif path.startswith("lib/mercurial/defaultrc/") and path.endswith(".rc"):
158 elif path.startswith("lib/mercurial/defaultrc/") and path.endswith(".rc"):
151 new_path = path[len("lib/mercurial/"):]
159 new_path = path[len("lib/mercurial/"):]
152 else:
160 else:
153 continue
161 continue
154
162
155 print("copying %s to %s" % (path, new_path))
163 print("copying %s to %s" % (path, new_path))
156 manifest.add_file(manifest.get_file(path), path = new_path)
164 manifest.add_file(manifest.get_file(path), path = new_path)
157
165
158 extra_install_files = VARS.get("extra_install_files", "")
166 extra_install_files = VARS.get("extra_install_files", "")
159 if extra_install_files:
167 if extra_install_files:
160 for extra in extra_install_files.split(","):
168 for extra in extra_install_files.split(","):
161 print("adding extra files from %s" % extra)
169 print("adding extra files from %s" % extra)
162 # TODO: I expected a ** glob to work, but it didn't.
170 # TODO: I expected a ** glob to work, but it didn't.
163 #
171 #
164 # TODO: I know this has forward-slash paths. As far as I can tell,
172 # TODO: I know this has forward-slash paths. As far as I can tell,
165 # backslashes don't ever match glob() expansions in
173 # backslashes don't ever match glob() expansions in
166 # tugger-starlark, even on Windows.
174 # tugger-starlark, even on Windows.
167 manifest.add_manifest(glob(include=[extra + "/*/*"], strip_prefix=extra+"/"))
175 manifest.add_manifest(glob(include=[extra + "/*/*"], strip_prefix=extra+"/"))
168
176
169 # We also install a handful of additional files.
177 # We also install a handful of additional files.
170 EXTRA_CONTRIB_FILES = [
178 EXTRA_CONTRIB_FILES = [
171 "bash_completion",
179 "bash_completion",
172 "hgweb.fcgi",
180 "hgweb.fcgi",
173 "hgweb.wsgi",
181 "hgweb.wsgi",
174 "logo-droplets.svg",
182 "logo-droplets.svg",
175 "mercurial.el",
183 "mercurial.el",
176 "mq.el",
184 "mq.el",
177 "tcsh_completion",
185 "tcsh_completion",
178 "tcsh_completion_build.sh",
186 "tcsh_completion_build.sh",
179 "xml.rnc",
187 "xml.rnc",
180 "zsh_completion",
188 "zsh_completion",
181 ]
189 ]
182
190
183 for f in EXTRA_CONTRIB_FILES:
191 for f in EXTRA_CONTRIB_FILES:
184 manifest.add_file(FileContent(path = ROOT + "/contrib/" + f), directory = "contrib")
192 manifest.add_file(FileContent(path = ROOT + "/contrib/" + f), directory = "contrib")
185
193
186 # Individual files with full source to destination path mapping.
194 # Individual files with full source to destination path mapping.
187 EXTRA_FILES = {
195 EXTRA_FILES = {
188 "contrib/hgk": "contrib/hgk.tcl",
196 "contrib/hgk": "contrib/hgk.tcl",
189 "contrib/win32/postinstall.txt": "ReleaseNotes.txt",
197 "contrib/win32/postinstall.txt": "ReleaseNotes.txt",
190 "contrib/win32/ReadMe.html": "ReadMe.html",
198 "contrib/win32/ReadMe.html": "ReadMe.html",
191 "doc/style.css": "doc/style.css",
199 "doc/style.css": "doc/style.css",
192 "COPYING": "Copying.txt",
200 "COPYING": "Copying.txt",
193 }
201 }
194
202
195 for source, dest in EXTRA_FILES.items():
203 for source, dest in EXTRA_FILES.items():
196 print("adding extra file %s" % dest)
204 print("adding extra file %s" % dest)
197 manifest.add_file(FileContent(path = ROOT + "/" + source), path = dest)
205 manifest.add_file(FileContent(path = ROOT + "/" + source), path = dest)
198
206
199 # And finally some wildcard matches.
207 # And finally some wildcard matches.
200 manifest.add_manifest(glob(
208 manifest.add_manifest(glob(
201 include = [ROOT + "/contrib/vim/*"],
209 include = [ROOT + "/contrib/vim/*"],
202 strip_prefix = ROOT + "/"
210 strip_prefix = ROOT + "/"
203 ))
211 ))
204 manifest.add_manifest(glob(
212 manifest.add_manifest(glob(
205 include = [ROOT + "/doc/*.html"],
213 include = [ROOT + "/doc/*.html"],
206 strip_prefix = ROOT + "/"
214 strip_prefix = ROOT + "/"
207 ))
215 ))
208
216
209 # But we don't ship hg-ssh on Windows, so exclude its documentation.
217 # But we don't ship hg-ssh on Windows, so exclude its documentation.
210 manifest.remove("doc/hg-ssh.8.html")
218 manifest.remove("doc/hg-ssh.8.html")
211
219
212 return manifest
220 return manifest
213
221
214
222
215 def make_msi(manifest):
223 def make_msi(manifest):
216 manifest = make_windows_install_layout(manifest)
224 manifest = make_windows_install_layout(manifest)
217
225
218 if "x86_64" in BUILD_TARGET_TRIPLE:
226 if "x86_64" in BUILD_TARGET_TRIPLE:
219 platform = "x64"
227 platform = "x64"
220 else:
228 else:
221 platform = "x86"
229 platform = "x86"
222
230
223 manifest.add_file(
231 manifest.add_file(
224 FileContent(path = ROOT + "/contrib/packaging/wix/COPYING.rtf"),
232 FileContent(path = ROOT + "/contrib/packaging/wix/COPYING.rtf"),
225 path = "COPYING.rtf",
233 path = "COPYING.rtf",
226 )
234 )
227 manifest.remove("Copying.txt")
235 manifest.remove("Copying.txt")
228 manifest.add_file(
236 manifest.add_file(
229 FileContent(path = ROOT + "/contrib/win32/mercurial.ini"),
237 FileContent(path = ROOT + "/contrib/win32/mercurial.ini"),
230 path = "defaultrc/mercurial.rc",
238 path = "defaultrc/mercurial.rc",
231 )
239 )
232 manifest.add_file(
240 manifest.add_file(
233 FileContent(filename = "editor.rc", content = "[ui]\neditor = notepad\n"),
241 FileContent(filename = "editor.rc", content = "[ui]\neditor = notepad\n"),
234 path = "defaultrc/editor.rc",
242 path = "defaultrc/editor.rc",
235 )
243 )
236
244
237 wix = WiXInstaller("hg", "%s-%s.msi" % (MSI_NAME, VERSION))
245 wix = WiXInstaller("hg", "%s-%s.msi" % (MSI_NAME, VERSION))
238
246
239 # Materialize files in the manifest to the install layout.
247 # Materialize files in the manifest to the install layout.
240 wix.add_install_files(manifest)
248 wix.add_install_files(manifest)
241
249
242 # From mercurial.wxs.
250 # From mercurial.wxs.
243 wix.install_files_root_directory_id = "INSTALLDIR"
251 wix.install_files_root_directory_id = "INSTALLDIR"
244
252
245 # Pull in our custom .wxs files.
253 # Pull in our custom .wxs files.
246 defines = {
254 defines = {
247 "PyOxidizer": "1",
255 "PyOxidizer": "1",
248 "Platform": platform,
256 "Platform": platform,
249 "Version": VERSION,
257 "Version": VERSION,
250 "Comments": "Installs Mercurial version %s" % VERSION,
258 "Comments": "Installs Mercurial version %s" % VERSION,
251 "PythonVersion": "3",
259 "PythonVersion": "3",
252 "MercurialHasLib": "1",
260 "MercurialHasLib": "1",
253 }
261 }
254
262
255 if EXTRA_MSI_FEATURES:
263 if EXTRA_MSI_FEATURES:
256 defines["MercurialExtraFeatures"] = EXTRA_MSI_FEATURES
264 defines["MercurialExtraFeatures"] = EXTRA_MSI_FEATURES
257
265
258 wix.add_wxs_file(
266 wix.add_wxs_file(
259 ROOT + "/contrib/packaging/wix/mercurial.wxs",
267 ROOT + "/contrib/packaging/wix/mercurial.wxs",
260 preprocessor_parameters=defines,
268 preprocessor_parameters=defines,
261 )
269 )
262
270
263 # Our .wxs references to other files. Pull those into the build environment.
271 # Our .wxs references to other files. Pull those into the build environment.
264 for f in ("defines.wxi", "guids.wxi", "COPYING.rtf"):
272 for f in ("defines.wxi", "guids.wxi", "COPYING.rtf"):
265 wix.add_build_file(f, ROOT + "/contrib/packaging/wix/" + f)
273 wix.add_build_file(f, ROOT + "/contrib/packaging/wix/" + f)
266
274
267 wix.add_build_file("mercurial.ico", ROOT + "/contrib/win32/mercurial.ico")
275 wix.add_build_file("mercurial.ico", ROOT + "/contrib/win32/mercurial.ico")
268
276
269 return wix
277 return wix
270
278
271
279
272 def register_code_signers():
280 def register_code_signers():
273 if not IS_WINDOWS:
281 if not IS_WINDOWS:
274 return
282 return
275
283
276 if SIGNING_PFX_PATH:
284 if SIGNING_PFX_PATH:
277 signer = code_signer_from_pfx_file(SIGNING_PFX_PATH, SIGNING_PFX_PASSWORD)
285 signer = code_signer_from_pfx_file(SIGNING_PFX_PATH, SIGNING_PFX_PASSWORD)
278 elif SIGNING_SUBJECT_NAME:
286 elif SIGNING_SUBJECT_NAME:
279 signer = code_signer_from_windows_store_subject(SIGNING_SUBJECT_NAME)
287 signer = code_signer_from_windows_store_subject(SIGNING_SUBJECT_NAME)
280 else:
288 else:
281 signer = None
289 signer = None
282
290
283 if signer:
291 if signer:
284 signer.set_time_stamp_server(TIME_STAMP_SERVER_URL)
292 signer.set_time_stamp_server(TIME_STAMP_SERVER_URL)
285 signer.activate()
293 signer.activate()
286
294
287
295
288 register_code_signers()
296 register_code_signers()
289
297
290 register_target("distribution", make_distribution)
298 register_target("distribution", make_distribution)
291 register_target("exe", make_exe, depends = ["distribution"])
299 register_target("exe", make_exe, depends = ["distribution"])
292 register_target("app", make_manifest, depends = ["distribution", "exe"], default = True)
300 register_target("app", make_manifest, depends = ["distribution", "exe"], default = True)
293 register_target("msi", make_msi, depends = ["app"])
301 register_target("msi", make_msi, depends = ["app"])
294
302
295 resolve_targets()
303 resolve_targets()
General Comments 0
You need to be logged in to leave comments. Login now