##// END OF EJS Templates
configitems: declare items in a TOML file...
configitems: declare items in a TOML file Mercurial ships with Rust code that also needs to read from the config. Having a way of presenting `configitems` to both Python and Rust is needed to prevent duplication, drift, and have the appropriate devel warnings. Abstracting away from Python means choosing a config format. No single format is perfect, and I have yet to come across a developer that doesn't hate all of them in some way. Since we have a strict no-dependencies policy for Mercurial, we either need to use whatever comes with Python, vendor a library, or implement a custom format ourselves. Python stdlib means using JSON, which doesn't support comments and isn't great for humans, or `configparser` which is an obscure, untyped format that nobody uses and doesn't have a commonplace Rust parser. Implementing a custom format is error-prone, tedious and subject to the same issues as picking an existing format. Vendoring opens us to the vast array of common config formats. The ones being picked for most modern software are YAML and TOML. YAML is older and common in the Python community, but TOML is much simpler and less error-prone. I would much rather be responsible for the <1000 lines of `tomli`, on top of TOML being the choice of the Rust community, with robust crates for reading it. The structure of `configitems.toml` is explained inline.

File last commit:

r49845:8d7eaff9 default
r51655:c51b178b default
Show More
pyoxidizer.py
173 lines | 5.1 KiB | text/x-python | PythonLexer
# pyoxidizer.py - Packaging support for PyOxidizer
#
# Copyright 2020 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
# no-check-code because Python 3 native.
import os
import pathlib
import shutil
import subprocess
import sys
import typing
from .downloads import download_entry
from .util import (
extract_zip_to_directory,
process_install_rules,
find_vc_runtime_dll,
)
STAGING_RULES_WINDOWS = [
('contrib/hgk', 'contrib/hgk.tcl'),
('contrib/hgweb.fcgi', 'contrib/'),
('contrib/hgweb.wsgi', 'contrib/'),
('contrib/logo-droplets.svg', 'contrib/'),
('contrib/mercurial.el', 'contrib/'),
('contrib/mq.el', 'contrib/'),
('contrib/tcsh_completion', 'contrib/'),
('contrib/tcsh_completion_build.sh', 'contrib/'),
('contrib/vim/*', 'contrib/vim/'),
('contrib/win32/postinstall.txt', 'ReleaseNotes.txt'),
('contrib/win32/ReadMe.html', 'ReadMe.html'),
('contrib/xml.rnc', 'contrib/'),
('doc/*.html', 'doc/'),
('doc/style.css', 'doc/'),
('COPYING', 'Copying.txt'),
]
STAGING_RULES_APP = [
('lib/mercurial/helptext/**/*.txt', 'helptext/'),
('lib/mercurial/defaultrc/*.rc', 'defaultrc/'),
('lib/mercurial/locale/**/*', 'locale/'),
('lib/mercurial/templates/**/*', 'templates/'),
]
STAGING_EXCLUDES_WINDOWS = [
"doc/hg-ssh.8.html",
]
def build_docs_html(source_dir: pathlib.Path):
"""Ensures HTML documentation is built.
This will fail if docutils isn't available.
(The HTML docs aren't built as part of `pip install` so we need to build them
out of band.)
"""
subprocess.run(
[sys.executable, str(source_dir / "setup.py"), "build_doc", "--html"],
cwd=str(source_dir),
check=True,
)
def run_pyoxidizer(
source_dir: pathlib.Path,
build_dir: pathlib.Path,
target_triple: str,
build_vars: typing.Optional[typing.Dict[str, str]] = None,
target: typing.Optional[str] = None,
) -> pathlib.Path:
"""Run `pyoxidizer` in an environment with access to build dependencies.
Returns the output directory that pyoxidizer would have used for build
artifacts. Actual build artifacts are likely in a sub-directory with the
name of the pyoxidizer build target that was built.
"""
build_vars = build_vars or {}
# We need to make gettext binaries available for compiling i18n files.
gettext_pkg, gettext_entry = download_entry('gettext', build_dir)
gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0]
gettext_root = build_dir / ('gettext-win-%s' % gettext_entry['version'])
if not gettext_root.exists():
extract_zip_to_directory(gettext_pkg, gettext_root)
extract_zip_to_directory(gettext_dep_pkg, gettext_root)
env = dict(os.environ)
env["PATH"] = "%s%s%s" % (
env["PATH"],
os.pathsep,
str(gettext_root / "bin"),
)
args = [
"pyoxidizer",
"build",
"--path",
str(source_dir / "rust" / "hgcli"),
"--release",
"--target-triple",
target_triple,
]
for k, v in sorted(build_vars.items()):
args.extend(["--var", k, v])
if target:
args.append(target)
subprocess.run(args, env=env, check=True)
return source_dir / "build" / "pyoxidizer" / target_triple / "release"
def create_pyoxidizer_install_layout(
source_dir: pathlib.Path,
build_dir: pathlib.Path,
out_dir: pathlib.Path,
target_triple: str,
):
"""Build Mercurial with PyOxidizer and copy additional files into place.
After successful completion, ``out_dir`` contains files constituting a
Mercurial install.
"""
run_pyoxidizer(source_dir, build_dir, target_triple)
build_dir = (
source_dir / "build" / "pyoxidizer" / target_triple / "release" / "app"
)
if out_dir.exists():
print("purging %s" % out_dir)
shutil.rmtree(out_dir)
# Now assemble all the files from PyOxidizer into the staging directory.
shutil.copytree(build_dir, out_dir)
# Move some of those files around. We can get rid of this once Mercurial
# is taught to use the importlib APIs for reading resources.
process_install_rules(STAGING_RULES_APP, build_dir, out_dir)
build_docs_html(source_dir)
if "windows" in target_triple:
process_install_rules(STAGING_RULES_WINDOWS, source_dir, out_dir)
# Write out a default editor.rc file to configure notepad as the
# default editor.
os.makedirs(out_dir / "defaultrc", exist_ok=True)
with (out_dir / "defaultrc" / "editor.rc").open(
"w", encoding="utf-8"
) as fh:
fh.write("[ui]\neditor = notepad\n")
for f in STAGING_EXCLUDES_WINDOWS:
p = out_dir / f
if p.exists():
print("removing %s" % p)
p.unlink()
# Add vcruntimeXXX.dll next to executable.
vc_runtime_dll = find_vc_runtime_dll(x64="x86_64" in target_triple)
shutil.copy(vc_runtime_dll, out_dir / vc_runtime_dll.name)