#!/usr/bin/env bash export VSCODE_QUALITY="stable" while getopts ":i" opt; do case "$opt" in i) export VSCODE_QUALITY="insider" ;; *) ;; esac done generate_rejects() { local PATCH_FILE="$1" if ! command -v python3 >/dev/null 2>&1; then echo "python3 not found; cannot create reject files for ${PATCH_FILE}" return 1 fi PATCH_FOR_REJECT="${PATCH_FILE}" python3 <<'PY' import os import pathlib import re import subprocess def chunk_needs_reject(raw_chunk: str) -> bool: """Return True when a patch chunk cannot be applied nor reversed.""" chunk = raw_chunk if raw_chunk.endswith("\n") else raw_chunk + "\n" def _run_git(extra_args): return subprocess.run( ["git", "apply", "--check", "--ignore-whitespace", *extra_args], input=chunk, text=True, capture_output=True, ) forward = _run_git([]) if forward.returncode == 0: return False reverse = _run_git(["--reverse"]) if reverse.returncode == 0: return False return True patch_path = os.environ["PATCH_FOR_REJECT"] with open(patch_path, "r", encoding="utf-8", errors="ignore") as src: content = src.read() chunks = re.split(r'(?m)^diff --git ', content) for chunk in chunks: chunk = chunk.strip() if not chunk: continue chunk = "diff --git " + chunk match = re.search(r'^diff --git a/(.*?) b/(.*?)$', chunk, re.MULTILINE) if not match: continue a_path, b_path = match.groups() candidate = b_path if b_path != "/dev/null" else a_path if candidate in ("/dev/null", ""): continue if candidate.startswith("../") or candidate.startswith("..\\") or candidate.startswith("/"): continue dest = pathlib.Path(candidate + ".rej") if not chunk_needs_reject(chunk): continue dest.parent.mkdir(parents=True, exist_ok=True) with dest.open("w", encoding="utf-8") as fh: fh.write(chunk) if not chunk.endswith("\n"): fh.write("\n") print(f"generated reject: {dest}") PY } check_file() { while [ $# -gt 1 ]; do git apply --reject "${1}" shift done if [[ -f "${1}.bak" ]]; then mv -f $1{.bak,} fi if [[ -f "${1}" ]]; then git apply --reject "../patches/helper/settings.patch" git add . git commit --no-verify -q -m "VSCODIUM HELPER" echo applying patch: "${1}" if ! git apply --ignore-whitespace "${1}"; then echo failed to apply patch "${1}" git apply --reject --verbose "${1}" if [[ -z "$( find . -name '*.rej' -print )" ]]; then echo "no .rej generated by git; creating fallback rejects for ${1}" if ! generate_rejects "${1}"; then echo "failed to generate reject files for ${1}" exit 1 fi if [[ -z "$( find . -name '*.rej' -print )" ]]; then echo "still no .rej after attempting to create them for ${1}" exit 1 fi fi while [[ -n "$( find . -name '*.rej' -print )" ]]; do find . -name '*.rej' -print read -rp "Press any key when the conflict have been resolved..." -n1 -s echo done git restore .vscode/settings.json git add . git diff --staged -U1 > "${1}" fi git add . git reset -q --hard HEAD~ fi } cd vscode || { echo "'vscode' dir not found"; exit 1; } git add . git reset -q --hard HEAD while [[ -n "$( git log -1 | grep "VSCODIUM HELPER" )" ]]; do git reset -q --hard HEAD~ done for FILE in ../patches/*.patch; do if [[ "${FILE}" == *"/fix-policies.patch" ]]; then check_file "../patches/fix-keymap.patch" "../patches/fix-policies.patch" else check_file "${FILE}" fi done if [[ "${VSCODE_QUALITY}" == "insider" ]]; then for FILE in ../patches/insider/*.patch; do check_file "${FILE}" done fi for ARCH in alpine linux osx windows; do for FILE in "../patches/${ARCH}/"*.patch; do if [[ "${ARCH}" == "linux" && "${FILE}" == *"/arch-"* ]] || [[ "${ARCH}" == "linux" && "${FILE}" == *"/fix-dependencies.patch" ]] || [[ "${ARCH}" == "windows" && "${FILE}" == *"/cli"* ]]; then echo "skip ${FILE}" else check_file "${FILE}" fi done if [[ "${ARCH}" == "linux" ]]; then check_file "../patches/optional-tree-sitter.patch" "../patches/linux/fix-dependencies.patch" check_file "../patches/cli.patch" "../patches/linux/arch-0-support.patch" check_file "../patches/cli.patch" "../patches/linux/arch-0-support.patch" "../patches/linux/arch-1-ppc64le.patch" check_file "../patches/cli.patch" "../patches/linux/arch-0-support.patch" "../patches/linux/arch-1-ppc64le.patch" "../patches/linux/arch-2-riscv64.patch" check_file "../patches/cli.patch" "../patches/linux/arch-0-support.patch" "../patches/linux/arch-1-ppc64le.patch" "../patches/linux/arch-2-riscv64.patch" "../patches/linux/arch-3-loong64.patch" check_file "../patches/cli.patch" "../patches/linux/arch-0-support.patch" "../patches/linux/arch-1-ppc64le.patch" "../patches/linux/arch-2-riscv64.patch" "../patches/linux/arch-3-loong64.patch" "../patches/linux/arch-4-s390x.patch" elif [[ "${ARCH}" == "windows" ]]; then check_file "../patches/cli.patch" "../patches/windows/cli.patch" fi for TARGET in client reh; do for FILE in "../patches/${ARCH}/${TARGET}/"*.patch; do check_file "${FILE}" done for FILE in "../patches/${ARCH}/${TARGET}/"*/*.patch; do check_file "${FILE}" done done done