git-cinnabar
555 строк · 19.0 Кб
1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5import hashlib6import os7
8import msys9from docker import DockerImage10from tasks import (11Task,12TaskEnvironment,13Tool,14parse_version,15)
16from util import build_commit17
18MERCURIAL_VERSION = "6.8"19# Not using 2.46.0 because of
20# https://lore.kernel.org/git/20240727191917.p64ul4jybpm2a7hm@glandium.org/
21GIT_VERSION = "2.45.2"22
23ALL_MERCURIAL_VERSIONS = (24"1.9.3",25"2.0.2",26"2.1.2",27"2.2.3",28"2.3.2",29"2.4.2",30"2.5.4",31"2.6.3",32"2.7.2",33"2.8.2",34"2.9.1",35"3.0.1",36"3.1.2",37"3.2.4",38"3.3.3",39"3.4.2",40"3.5.2",41"3.6.3",42"3.7.3",43"3.8.4",44"3.9.2",45"4.0.2",46"4.1.3",47"4.2.2",48"4.3.3",49"4.4.2",50"4.5.3",51"4.6.2",52"4.7.2",53"4.8.2",54"4.9.1",55"5.0.2",56"5.1.2",57"5.2.2",58"5.3.2",59"5.4.2",60"5.5.2",61"5.6.1",62"5.7.1",63"5.8.1",64"5.9.3",65"6.0.3",66"6.1.4",67"6.2.3",68"6.3.3",69"6.4.2",70"6.5.3",71"6.6.3",72"6.7.4",73"6.8",74)
75
76SOME_MERCURIAL_VERSIONS = (77"1.9.3",78"2.5.4",79"3.4.2",80)
81
82assert MERCURIAL_VERSION in ALL_MERCURIAL_VERSIONS83assert all(v in ALL_MERCURIAL_VERSIONS for v in SOME_MERCURIAL_VERSIONS)84
85
86def nproc(env):87if env.os == "macos":88return "sysctl -n hw.physicalcpu"89return "nproc --all"90
91
92class Git(Task, metaclass=Tool):93PREFIX = "git"94
95def __init__(self, os_and_version):96(os, version) = os_and_version.split(".", 1)97self.os = os98if os.endswith("osx"):99build_image = TaskEnvironment.by_name("{}.build".format(os))100else:101build_image = DockerImage.by_name("build-tools")102if os == "linux" or os.endswith("osx"):103h = hashlib.sha1(build_image.hexdigest.encode())104h.update(b"v4" if version == GIT_VERSION else b"v3")105if os == "linux":106description = "git v{}".format(version)107else:108env = build_image109description = "git v{} {} {}".format(version, env.os, env.cpu)110Task.__init__(111self,112task_env=build_image,113description=description,114index="{}.git.v{}".format(h.hexdigest(), version),115expireIn="26 weeks",116command=Task.checkout(117"git://git.kernel.org/pub/scm/git/git.git",118"v{}".format(version),119dest="git",120)121+ Task.checkout()122+ (123[124"patch -d git -p1 < repo/CI/git-transport-disconnect.diff",125]126if version == GIT_VERSION127else []128)129+ [130"make -C git -j$({}) install prefix=/ NO_GETTEXT=1"131" NO_OPENSSL=1 NO_TCLTK=1 NO_UNCOMPRESS2=1"132" DESTDIR=$PWD/git".format(nproc(build_image)),133"tar -c git | zstd -c > $ARTIFACTS/git-{}.tar.zst".format(version),134],135artifact="git-{}.tar.zst".format(version),136)137else:138env = TaskEnvironment.by_name("{}.build".format(os))139raw_version = version140if "windows" not in version:141version = {142version: version + ".windows.1",143"2.17.1": "2.17.1.windows.2",144}.get(version)145if version.endswith(".windows.1"):146min_ver = version[: -len(".windows.1")]147else:148min_ver = version.replace("windows.", "")149h = hashlib.sha1(env.hexdigest.encode())150h.update(b"v1")151Task.__init__(152self,153task_env=build_image,154description="git v{} {} {}".format(version, env.os, env.cpu),155index="{}.git.v{}".format(h.hexdigest(), raw_version),156expireIn="26 weeks",157command=[158"curl -L https://github.com/git-for-windows/git/releases/"159"download/v{}/MinGit-{}-{}-bit.zip"160" -o git.zip".format(version, min_ver, msys.bits(env.cpu)),161"unzip -d git git.zip",162"curl -L https://github.com/git-for-windows/git/releases/"163"download/v{}/Git-{}-{}-bit.tar.bz2 | "164"tar -C git --no-same-owner -jx "165"{}/libexec/git-core/git-http-backend.exe".format(166version,167min_ver,168msys.bits(env.cpu),169msys.mingw(env.cpu).lower(),170),171"tar -c git | zstd -c > $ARTIFACTS/git-{}.tar.zst".format(172raw_version
173),174],175artifact="git-{}.tar.zst".format(raw_version),176)177
178def mount(self):179return {"directory:git": self}180
181def install(self):182if self.os.endswith(("linux", "osx")):183return [184"export PATH=$PWD/git/bin:$PATH",185"export GIT_EXEC_PATH=$PWD/git/libexec/git-core",186"export GIT_TEMPLATE_DIR=$PWD/git/share/git-core/templates",187]188else:189return []190
191
192class Hg(Task, metaclass=Tool):193PREFIX = "hg"194
195def __init__(self, os_and_version):196(os, version) = os_and_version.split(".", 1)197(version, suffix, _) = version.partition(".py3")198if (199suffix
200or len(version) == 40201or parse_version(version) >= parse_version("6.2")202):203python = "python3"204else:205python = "python2.7"206if os == "linux":207env = TaskEnvironment.by_name("{}.build-tools".format(os))208else:209env = TaskEnvironment.by_name("{}.build".format(os))210kwargs = {}211
212if len(version) == 40:213# Assume it's a sha1214pretty_version = "r{}{}".format(version, suffix)215artifact_version = "99.0"216expire = "2 weeks"217else:218pretty_version = "v{}{}".format(version, suffix)219artifact_version = version220expire = "26 weeks"221desc = "hg {}".format(pretty_version)222if os == "linux":223platform_tag = "linux_x86_64"224if python == "python3":225python_tag = "cp39"226abi_tag = "cp39"227else:228python_tag = "cp27"229abi_tag = "cp27mu"230else:231desc = "{} {} {}".format(desc, env.os, env.cpu)232if os.endswith("osx"):233py_host_plat = "macosx-{}-{}".format(env.os_version, env.cpu)234platform_tag = py_host_plat.replace(".", "_").replace("-", "_")235if python == "python3":236python_tag = "cp311" if os == "arm64-osx" else "cp39"237abi_tag = python_tag238else:239python_tag = "cp27"240abi_tag = "cp27m"241env_ = kwargs.setdefault("env", {})242env_.setdefault("MACOSX_DEPLOYMENT_TARGET", env.os_version)243env_.setdefault("ARCHFLAGS", "-arch {}".format(env.cpu))244env_.setdefault("_PYTHON_HOST_PLATFORM", py_host_plat)245else:246if python == "python3":247platform_tag = "mingw_x86_64"248python_tag = "cp310"249abi_tag = "cp310"250else:251platform_tag = "mingw"252python_tag = "cp27"253abi_tag = "cp27m"254
255artifact = "mercurial-{{}}-{}-{}-{}.whl".format(256python_tag,257abi_tag,258platform_tag,259)260
261pre_command = []262if len(version) == 40:263hg = self.by_name("{}.{}".format(os, MERCURIAL_VERSION))264kwargs.setdefault("mounts", []).append(hg.mount())265pre_command.extend(hg.install())266pre_command.extend(267[268"hg clone https://www.mercurial-scm.org/repo/hg"269" -r {} mercurial-{}".format(version, version),270"rm -rf mercurial-{}/.hg".format(version),271"echo tag: {} > mercurial-{}/.hg_archival.txt".format(272artifact_version, version273),274]275)276# 2.6.2 is the first version available on pypi277elif parse_version("2.6.2") <= parse_version(version) and parse_version(278version
279) < parse_version("6.2"):280# pip download does more than download, and while it runs setup.py281# for version 6.2, a DistutilsPlatformError exception is thrown on282# Windows.283pre_command.append(284"{} -m pip download --no-binary mercurial --no-deps"285" --progress-bar off mercurial=={}".format(python, version)286)287else:288url = "https://mercurial-scm.org/release/mercurial-{}.tar.gz"289pre_command.append("curl -sLO {}".format(url.format(version)))290
291if len(version) != 40:292pre_command.append("tar -zxf mercurial-{}.tar.gz".format(version))293
294if os.startswith("mingw"):295# Work around https://bz.mercurial-scm.org/show_bug.cgi?id=6654296# and https://bz.mercurial-scm.org/show_bug.cgi?id=6757297pre_command.append(298'sed -i "s/, output_dir=self.build_temp/'299", output_dir=self.build_temp, extra_postargs=[$EXTRA_FLAGS]/;"300"/self.addlongpathsmanifest/d;"301'" mercurial-{}/setup.py'.format(version)302)303if python == "python3":304kwargs.setdefault("env", {}).setdefault("EXTRA_FLAGS", '"-municode"')305pre_command.append(306'sed -i "s/ifdef __GNUC__/if 0/"'307" mercurial-{}/mercurial/exewrapper.c".format(version)308)309
310h = hashlib.sha1(env.hexdigest.encode())311h.update(artifact.encode())312if os.endswith("osx"):313h.update(b"v2")314elif os.startswith("mingw"):315h.update(b"v4")316else:317h.update(b"v1")318
319Task.__init__(320self,321task_env=env,322description=desc,323index="{}.hg.{}".format(h.hexdigest(), pretty_version),324expireIn=expire,325command=pre_command326+ [327# pyproject.toml enables PEP 517, which can't be disabled.328# pip wheel doesn't accept --build-option when PEP 517 is329# enabled. --build-option is necessary on msys2 because330# of problems with the bdist-dir otherwise.331"rm -f mercurial-{}/pyproject.toml".format(version),332"{} -m pip wheel -v --build-option -b --build-option"333" $PWD/wheel -w $ARTIFACTS ./mercurial-{}".format(python, version),334],335artifact=artifact.format(artifact_version),336**kwargs,337)338
339def mount(self):340return {f"file:{os.path.basename(self.artifacts[0])}": self}341
342def install(self):343filename = os.path.basename(self.artifacts[0])344if "cp3" in filename:345python = "python3"346else:347python = "python2.7"348return ["{} -m pip install {}".format(python, filename)]349
350
351def install_rust(version="1.80.0", target="x86_64-unknown-linux-gnu"):352rustup_opts = "-y --default-toolchain none"353cargo_dir = "$HOME/.cargo/bin/"354rustup = cargo_dir + "rustup"355rust_install = [356"curl -o rustup.sh https://sh.rustup.rs",357"sh rustup.sh {rustup_opts}",358"{rustup} install {version} --profile minimal",359"{rustup} default {version}",360"PATH={cargo_dir}:$PATH",361"{rustup} target add {target}",362]363loc = locals()364return [r.format(**loc) for r in rust_install]365
366
367class Build(Task, metaclass=Tool):368PREFIX = "build"369
370def __init__(self, os_and_variant):371os, variant = (os_and_variant.split(".", 1) + [""])[:2]372env = TaskEnvironment.by_name(373"{}.build".format(os.replace("arm64-linux", "linux"))374)375if os.startswith("mingw"):376build_env = TaskEnvironment.by_name("linux.build")377else:378build_env = env379
380artifact = "git-cinnabar"381if os.startswith("mingw"):382artifact += ".exe"383artifacts = [artifact]384
385def prefix(p, s):386return p + s if s else s387
388hash = None389head = None390desc_variant = variant391extra_commands = []392environ = {393"WARNINGS_AS_ERRORS": "1",394}395cargo_flags = ["-vv", "--release"]396cargo_features = ["self-update", "gitdev", "xz2/static", "bzip2/static"]397rust_version = None398if variant == "asan":399if os.endswith("osx"):400opt = "-O2"401else:402opt = "-Og"403environ["TARGET_CFLAGS"] = " ".join(404[405opt,406"-g",407"-fsanitize=address",408"-fno-omit-frame-pointer",409"-fPIC",410]411)412environ["RUSTFLAGS"] = " ".join(413[414"-Zsanitizer=address",415"-Copt-level=1",416"-Cdebuginfo=full",417"-Cforce-frame-pointers=yes",418]419)420elif variant == "coverage":421environ["TARGET_CFLAGS"] = " ".join(422[423"-coverage",424"-fPIC",425]426)427artifacts += ["coverage.zip"]428extra_commands = [429"(cd repo && zip $ARTIFACTS/coverage.zip"430' $(find . -name "*.gcno" -not -name "build_script*"))',431]432environ["RUSTFLAGS"] = " ".join(433[434"-Zprofile",435"-Ccodegen-units=1",436"-Cinline-threshold=0",437]438)439# Build without --release440cargo_flags.remove("--release")441environ["CARGO_INCREMENTAL"] = "0"442elif variant.startswith("old:"):443head = variant[4:]444hash = build_commit(head)445variant = ""446elif variant.startswith("rust-"):447rust_version = variant[5:]448elif variant:449raise Exception("Unknown variant: {}".format(variant))450
451if "osx" not in os:452environ["CC"] = "clang-18"453if os in ("linux", "arm64-linux"):454cargo_features.append("curl-compat")455
456if os.startswith("mingw"):457cpu = msys.msys_cpu(env.cpu)458rust_target = "{}-pc-windows-gnu".format(cpu)459elif os.startswith("osx"):460rust_target = "x86_64-apple-darwin"461elif os.startswith("arm64-osx"):462rust_target = "aarch64-apple-darwin"463elif os == "linux":464rust_target = "x86_64-unknown-linux-gnu"465elif os == "arm64-linux":466rust_target = "aarch64-unknown-linux-gnu"467if "osx" not in os:468for target in dict.fromkeys(469["x86_64-unknown-linux-gnu", rust_target]470).keys():471arch = {472"x86_64": "amd64",473"aarch64": "arm64",474}[target.partition("-")[0]]475multiarch = target.replace("unknown-", "")476TARGET = target.replace("-", "_").upper()477environ[f"CARGO_TARGET_{TARGET}_LINKER"] = environ["CC"]478if "linux" in os:479extra_link_arg = f"--sysroot=/sysroot-{arch}"480if os.startswith("mingw"):481extra_link_arg = f"-L/usr/lib/gcc/{cpu}-w64-mingw32/10-win32"482environ[f"CARGO_TARGET_{TARGET}_RUSTFLAGS"] = (483f"-C link-arg=--target={target} "484+ f"-C link-arg={extra_link_arg} "485+ "-C link-arg=-fuse-ld=lld-18"486)487rustflags = environ.pop("RUSTFLAGS", None)488if rustflags:489environ[f"CARGO_TARGET_{TARGET}_RUSTFLAGS"] += f" {rustflags}"490if "linux" in os:491environ[f"CFLAGS_{target}"] = f"--sysroot=/sysroot-{arch}"492if "linux" in os:493environ["PKG_CONFIG_PATH"] = ""494environ["PKG_CONFIG_SYSROOT_DIR"] = f"/sysroot-{arch}"495environ["PKG_CONFIG_LIBDIR"] = ":".join(496(497f"/sysroot-{arch}/usr/lib/pkgconfig",498f"/sysroot-{arch}/usr/lib/{multiarch}/pkgconfig",499f"/sysroot-{arch}/usr/share/pkgconfig",500)501)502if variant in ("coverage", "asan"):503environ["RUSTC_BOOTSTRAP"] = "1"504if rust_version:505rust_install = install_rust(rust_version, target=rust_target)506else:507rust_install = install_rust(target=rust_target)508cargo_flags.extend(["--target", rust_target])509if cargo_features:510cargo_flags.extend(["--features", ",".join(cargo_features)])511for key, value in list(environ.items()):512# RUSTFLAGS values in the environment override builds.rustflags513# from .cargo/config.toml.514if "RUSTFLAGS" in key:515environ[key] = value + " -Cforce-unwind-tables=yes"516
517hash = hash or build_commit()518
519if os.startswith("osx"):520environ.setdefault("MACOSX_DEPLOYMENT_TARGET", "10.7")521if os.startswith("arm64-osx"):522environ.setdefault("MACOSX_DEPLOYMENT_TARGET", "11.0")523
524cpu = "arm64" if os == "arm64-linux" else env.cpu525Task.__init__(526self,527task_env=build_env,528description="build {} {}{}".format(env.os, cpu, prefix(" ", desc_variant)),529index="build.{}.{}.{}{}".format(hash, env.os, cpu, prefix(".", variant)),530expireIn="26 weeks",531command=Task.checkout(commit=head)532+ rust_install533+ [534"(cd repo ; cargo build {})".format(" ".join(cargo_flags)),535"mv repo/target/{}/{}/{} $ARTIFACTS/".format(536rust_target,537"release" if "--release" in cargo_flags else "debug",538artifact,539),540]541+ extra_commands,542artifacts=artifacts,543env=environ,544)545
546def mount(self):547return {f"file:{os.path.basename(self.artifacts[0])}": self}548
549def install(self):550filename = os.path.basename(self.artifacts[0])551return [552f"cp {filename} repo/",553"chmod +x repo/{}".format(filename),554"$PWD/repo/{} setup".format(filename),555]556