--- a/etc/build.props Fri Mar 04 22:50:58 2022 +0100
+++ b/etc/build.props Fri Mar 04 22:53:49 2022 +0100
@@ -30,6 +30,7 @@
src/Pure/Admin/build_status.scala \
src/Pure/Admin/build_vampire.scala \
src/Pure/Admin/build_verit.scala \
+ src/Pure/Admin/build_vscodium.scala \
src/Pure/Admin/build_zipperposition.scala \
src/Pure/Admin/check_sources.scala \
src/Pure/Admin/ci_profile.scala \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/build_vscodium.scala Fri Mar 04 22:53:49 2022 +0100
@@ -0,0 +1,278 @@
+/* Title: Pure/Admin/build_vscodium.scala
+ Author: Makarius
+
+Build component for VSCodium (cross-compiled from sources for all platforms).
+*/
+
+package isabelle
+
+
+import java.security.MessageDigest
+import java.util.Base64
+
+
+object Build_VSCodium
+{
+ /* patch resources */
+
+ // see https://github.com/microsoft/vscode/blob/main/build/gulpfile.vscode.js
+ // function computeChecksum(filename)
+
+ def file_checksum(path: Path): String =
+ {
+ val digest = MessageDigest.getInstance("MD5")
+ digest.update(Bytes.read(path).array)
+ Bytes(Base64.getEncoder.encode(digest.digest()))
+ .text.replaceAll("=", "")
+ }
+
+ def patch_resources(dir: Path): Unit =
+ {
+ HTML.init_fonts(dir + Path.explode("app/out/vs/base/browser/ui"))
+
+ val workbench_css = dir + Path.explode("app/out/vs/workbench/workbench.desktop.main.css")
+ val checksum1 = file_checksum(workbench_css)
+ File.append(workbench_css, "\n\n" + HTML.fonts_css_dir(prefix = "../base/browser/ui"))
+ val checksum2 = file_checksum(workbench_css)
+
+ val file_name = workbench_css.file_name
+ File.change_lines(dir + Path.explode("app/product.json")) { _.map(line =>
+ if (line.containsSlice(file_name) && line.contains(checksum1)) {
+ line.replace(checksum1, checksum2)
+ }
+ else line)
+ }
+ }
+
+
+ /* platform info */
+
+ sealed case class Platform_Info(
+ platform: Platform.Family.Value, build_name: String, env: List[String])
+ {
+ def platform_dir(dir: Path): Path =
+ {
+ val platform_name =
+ if (platform == Platform.Family.windows) Platform.Family.native(platform)
+ else Platform.Family.standard(platform)
+ dir + Path.explode(platform_name)
+ }
+
+ def resources_dir(dir: Path): Path =
+ {
+ val resources =
+ if (platform == Platform.Family.macos) "VSCodium.app/Contents/Resources"
+ else "resources"
+ dir + Path.explode(resources)
+ }
+
+ def build_dir(dir: Path): Path = dir + Path.explode(build_name)
+
+ def environment(version: String): String =
+ (("MS_TAG=" + Bash.string(version)) :: "SHOULD_BUILD=yes" :: "VSCODE_ARCH=x64" :: env)
+ .map(s => "export " + s + "\n").mkString
+ }
+
+ private val platform_info: Map[Platform.Family.Value, Platform_Info] =
+ Iterator(
+ Platform_Info(Platform.Family.linux, "VSCode-linux-x64",
+ List("OS_NAME=linux", "SKIP_LINUX_PACKAGES=True")),
+ Platform_Info(Platform.Family.linux_arm, "VSCode-linux-arm64",
+ List("OS_NAME=linux", "SKIP_LINUX_PACKAGES=True", "VSCODE_ARCH=arm64")),
+ Platform_Info(Platform.Family.macos, "VSCode-darwin-x64",
+ List("OS_NAME=osx")),
+ Platform_Info(Platform.Family.windows, "VSCode-win32-x64",
+ List("OS_NAME=windows",
+ "SHOULD_BUILD_ZIP=no",
+ "SHOULD_BUILD_EXE_SYS=no",
+ "SHOULD_BUILD_EXE_USR=no",
+ "SHOULD_BUILD_MSI=no",
+ "SHOULD_BUILD_MSI_NOUP=no")))
+ .map(info => info.platform -> info).toMap
+
+
+ /* build vscodium */
+
+ val default_repository_url = "https://github.com/VSCodium/vscodium.git"
+ val default_version = "1.64.2"
+ def default_platforms: List[Platform.Family.Value] = Platform.Family.list
+
+ private def vscodium_exe(dir: Path): Path = dir + Path.explode("bin/codium")
+
+ private def macos_exe: String =
+"""#!/usr/bin/env bash
+
+unset CDPATH
+VSCODE_PATH="$(cd "$(dirname "$0")"/../VSCodium.app/Contents; pwd)"
+
+ELECTRON="$VSCODE_PATH/MacOS/Electron"
+CLI="$VSCODE_PATH/Resources/app/out/cli.js"
+ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --ms-enable-electron-run-as-node "$@"
+exit $?
+"""
+
+ def build_vscodium(
+ target_dir: Path = Path.current,
+ repository_url: String = default_repository_url,
+ version: String = default_version,
+ platforms: List[Platform.Family.Value] = default_platforms,
+ verbose: Boolean = false,
+ progress: Progress = new Progress): Unit =
+ {
+ /* prerequisites */
+
+ Linux.check_system()
+
+ Isabelle_System.require_command("git")
+ if (platforms.nonEmpty) {
+ Isabelle_System.require_command("node")
+ Isabelle_System.require_command("yarn")
+ Isabelle_System.require_command("jq")
+ }
+ if (platforms.contains(Platform.Family.windows)) {
+ Isabelle_System.require_command("wine")
+ }
+
+
+ /* component */
+
+ val component_name = "vscodium-" + version
+ val component_dir = Isabelle_System.new_directory(target_dir + Path.basic(component_name))
+ progress.echo("Component " + component_dir)
+
+
+ /* build */
+
+ for (platform <- platforms) {
+ val info =
+ platform_info.getOrElse(platform, error("No platform info for " + quote(platform.toString)))
+
+ progress.echo("Building " + platform + " ...")
+
+ Isabelle_System.with_tmp_dir("vscodium")(vscodium_dir =>
+ {
+ def execute(lines: String*): Unit =
+ progress.bash(("set -e" :: info.environment(version) :: lines.toList).mkString("\n"),
+ cwd = vscodium_dir.file, echo = verbose).check
+
+ execute(
+ "git clone -n " + Bash.string(repository_url) + " .",
+ "git checkout -q " + Bash.string(version),
+ "./get_repo.sh")
+
+ for (name <- Seq("vscode/build/lib/electron.js", "vscode/build/lib/electron.ts")) {
+ File.change(vscodium_dir + Path.explode(name), strict = true) {
+ _.replace("""'resources/darwin/' + icon + '.icns'""",
+ """'resources/darwin/' + icon.toLowerCase() + '.icns'""")
+ }
+ }
+
+ execute("./build.sh")
+
+ val platform_dir = info.platform_dir(component_dir)
+ Isabelle_System.copy_dir(info.build_dir(vscodium_dir), platform_dir)
+ Isabelle_System.copy_file(vscodium_dir + Path.explode("LICENSE"), component_dir)
+
+ patch_resources(info.resources_dir(platform_dir))
+
+ val exe = vscodium_exe(platform_dir)
+ Isabelle_System.make_directory(exe.dir)
+
+ platform match {
+ case Platform.Family.macos =>
+ File.write(exe, macos_exe)
+ File.set_executable(exe, true)
+ case Platform.Family.windows =>
+ val files1 = File.find_files(exe.dir.file)
+ val files2 =
+ File.find_files(platform_dir.file,
+ pred = file => file.getName.endsWith(".exe") || file.getName.endsWith(".dll"))
+ for (file <- files1 ::: files2) File.set_executable(File.path(file), true)
+ Isabelle_System.bash("chmod -R o-w " + File.bash_path(platform_dir))
+ case _ =>
+ }
+ })
+ }
+
+
+ /* settings */
+
+ val etc_dir = Isabelle_System.make_directory(component_dir + Path.explode("etc"))
+ File.write(etc_dir + Path.basic("settings"),
+ """# -*- shell-script -*- :mode=shellscript:
+
+ISABELLE_VSCODIUM_HOME="$COMPONENT/${ISABELLE_WINDOWS_PLATFORM64:-$ISABELLE_PLATFORM64}"
+
+case "$ISABELLE_PLATFORM_FAMILY" in
+ linux)
+ ISABELLE_ELECTRON="$ISABELLE_VSCODIUM_HOME/codium"
+ ;;
+ macos)
+ ISABELLE_ELECTRON="$ISABELLE_VSCODIUM_HOME/VSCodium.app/Contents/MacOS/Electron"
+ ;;
+ windows)
+ ISABELLE_ELECTRON="$ISABELLE_VSCODIUM_HOME/VSCodium.exe"
+ ;;
+esac
+""")
+
+
+ /* README */
+
+ File.write(component_dir + Path.basic("README"),
+ "This is VSCodium " + version + " from " + repository_url +
+"""
+
+It has been built from sources using "isabelle build_vscodium": this applies
+a few changes required for Isabelle/VSCode.
+
+
+ Makarius
+ """ + Date.Format.date(Date.now()) + "\n")
+ }
+
+
+ /* Isabelle tool wrapper */
+
+ val isabelle_tool =
+ Isabelle_Tool("build_vscodium", "build component for VSCodium",
+ Scala_Project.here, args =>
+ {
+ var target_dir = Path.current
+ var repository_url = default_repository_url
+ var version = default_version
+ var platforms = default_platforms
+ var verbose = false
+
+ val getopts = Getopts("""
+Usage: vscode_setup [OPTIONS]
+
+ Options are:
+ -D DIR target directory (default ".")
+ -U URL repository URL
+ (default: """" + default_repository_url + """")
+ -V VERSION version (default: """" + default_version + """")
+ -p NAMES platform families
+ (default: """ + quote(platforms.mkString(",")) + """)
+ -v verbose
+
+ Build VSCodium from sources and turn it into an Isabelle component.
+
+ The build platform needs to be Linux with nodejs/yarn, jq, and wine
+ for targeting Windows.
+""",
+ "D:" -> (arg => target_dir = Path.explode(arg)),
+ "U:" -> (arg => repository_url = arg),
+ "V:" -> (arg => version = arg),
+ "p:" -> (arg => platforms = Library.space_explode(',', arg).map(Platform.Family.parse)),
+ "v" -> (_ => verbose = true))
+
+ val more_args = getopts(args)
+ if (more_args.nonEmpty) getopts.usage()
+
+ val progress = new Console_Progress()
+
+ build_vscodium(target_dir = target_dir, repository_url = repository_url,
+ version = version, platforms = platforms, verbose = verbose, progress = progress)
+ })
+}
--- a/src/Pure/System/isabelle_tool.scala Fri Mar 04 22:50:58 2022 +0100
+++ b/src/Pure/System/isabelle_tool.scala Fri Mar 04 22:53:49 2022 +0100
@@ -231,6 +231,7 @@
Build_Status.isabelle_tool,
Build_Vampire.isabelle_tool,
Build_VeriT.isabelle_tool,
+ Build_VSCodium.isabelle_tool,
Build_Zipperposition.isabelle_tool,
Check_Sources.isabelle_tool,
Components.isabelle_tool,
--- a/src/Tools/VSCode/src/vscode_setup.scala Fri Mar 04 22:50:58 2022 +0100
+++ b/src/Tools/VSCode/src/vscode_setup.scala Fri Mar 04 22:53:49 2022 +0100
@@ -23,6 +23,8 @@
def vscode_version: String = Isabelle_System.getenv_strict("ISABELLE_VSCODE_VERSION")
def vscode_workspace: Path = Path.variable("ISABELLE_VSCODE_WORKSPACE")
+ def vscodium_home: Path = Path.variable("ISABELLE_VSCODIUM_HOME")
+
def exe_path(dir: Path): Path = dir + Path.explode("bin/codium")
def vscode_installation(version: String, platform: Platform.Family.Value): (Boolean, Path) =
@@ -139,7 +141,11 @@
}
if (check) {
- if (install_ok) {
+ if (vscodium_home.is_dir) {
+ init_workspace(vscode_workspace)
+ progress.echo(vscodium_home.expand.implode)
+ }
+ else if (install_ok) {
init_workspace(vscode_workspace)
progress.echo(install_dir.expand.implode)
}