provide "isabelle caddy_setup" and "isabelle caddy";
authorwenzelm
Wed, 07 May 2025 21:52:22 +0200
changeset 82615 3e20da339306
parent 82614 6a2808a48c51
child 82616 c1871d013556
provide "isabelle caddy_setup" and "isabelle caddy"; proper go-1.24.1 as required by xcaddy-0.4.4;
etc/build.props
etc/settings
lib/Tools/caddy
src/Pure/System/isabelle_tool.scala
src/Pure/Tools/caddy_setup.scala
--- a/etc/build.props	Wed May 07 11:58:10 2025 +0200
+++ b/etc/build.props	Wed May 07 21:52:22 2025 +0200
@@ -218,6 +218,7 @@
   src/Pure/Thy/thy_element.scala \
   src/Pure/Thy/thy_header.scala \
   src/Pure/Thy/thy_syntax.scala \
+  src/Pure/Tools/caddy_setup.scala \
   src/Pure/Tools/check_keywords.scala \
   src/Pure/Tools/debugger.scala \
   src/Pure/Tools/doc.scala \
@@ -351,6 +352,7 @@
   isabelle.Bibtex$File_Format \
   isabelle.Build$Engine$Default \
   isabelle.Build_Schedule$Build_Engine \
+  isabelle.Caddy_Setup \
   isabelle.CI_Jobs \
   isabelle.Document_Build$Build_Engine \
   isabelle.Document_Build$LIPIcs_LuaLaTeX_Engine \
--- a/etc/settings	Wed May 07 11:58:10 2025 +0200
+++ b/etc/settings	Wed May 07 21:52:22 2025 +0200
@@ -187,10 +187,13 @@
 
 
 ###
-### Go
+### Go and Caddy
 ###
 
-ISABELLE_GO_VERSION="1.24.3"
+ISABELLE_GO_VERSION="1.24.1"
+
+ISABELLE_CADDY_SETUP_VERSION="2.10.0"
+ISABELLE_CADDY_SETUP_MODULES="github.com/jasonlovesdoggo/caddy-defender github.com/mholt/caddy-ratelimit"
 
 
 ###
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Tools/caddy	Wed May 07 21:52:22 2025 +0200
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+#
+# Author: Makarius
+#
+# DESCRIPTION: invoke caddy within the Isabelle environment
+
+if [ -z "$ISABELLE_CADDY" ]; then
+  echo "Missing Caddy installation: need to run \"isabelle caddy_setup\" first" >&2
+  exit 2
+else
+  exec "$ISABELLE_CADDY" "$@"
+fi
--- a/src/Pure/System/isabelle_tool.scala	Wed May 07 11:58:10 2025 +0200
+++ b/src/Pure/System/isabelle_tool.scala	Wed May 07 21:52:22 2025 +0200
@@ -132,6 +132,7 @@
   Build_Manager.isabelle_tool2,
   Build_Schedule.isabelle_tool,
   Build_CI.isabelle_tool,
+  Caddy_Setup.isabelle_tool,
   Doc.isabelle_tool,
   Docker_Build.isabelle_tool,
   Document_Build.isabelle_tool,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Tools/caddy_setup.scala	Wed May 07 21:52:22 2025 +0200
@@ -0,0 +1,188 @@
+/*  Title:      Pure/Tools/caddy_setup.scala
+    Author:     Makarius
+
+Dynamic setup of Caddy component.
+*/
+
+package isabelle
+
+
+object Caddy_Setup {
+  /* platform information */
+
+  sealed case class Platform_Info(platform: String, xcaddy_template: String)
+  extends Platform.Info {
+    def xcaddy_download(url: String, version: String): String =
+      Url.append_path(url, xcaddy_template.replace("{V}", version))
+  }
+
+  val all_platforms: List[Platform_Info] =
+    List(
+      Platform_Info("arm64-darwin", "v{V}/xcaddy_{V}_mac_arm64.tar.gz"),
+      Platform_Info("arm64-linux", "v{V}/xcaddy_{V}_linux_arm64.tar.gz"),
+      Platform_Info("x86_64-darwin", "v{V}/xcaddy_{V}_mac_amd64.tar.gz"),
+      Platform_Info("x86_64-linux", "v{V}/xcaddy_{V}_linux_amd64.tar.gz"),
+      Platform_Info("x86_64-windows", "v{V}/xcaddy_{V}_windows_amd64.zip"))
+
+
+  /* download and setup */
+
+  def default_target_dir: Path = Components.default_components_base
+  def default_caddy_version: String = Isabelle_System.getenv_strict("ISABELLE_CADDY_SETUP_VERSION")
+  def default_caddy_modules: String = Isabelle_System.getenv_strict("ISABELLE_CADDY_SETUP_MODULES")
+  def default_xcaddy_url: String = "https://github.com/caddyserver/xcaddy/releases/download"
+  def default_xcaddy_version: String = "0.4.4"
+
+  def show_settings(): List[String] =
+    for (a <- List("ISABELLE_CADDY_SETUP_VERSION", "ISABELLE_CADDY_SETUP_MODULES"))
+      yield {
+        val b = Isabelle_System.getenv(a)
+        a + "=" + quote(b)
+      }
+
+  def caddy_setup(
+    caddy_version: String = default_caddy_version,
+    caddy_modules: String = default_caddy_modules,
+    xcaddy_url: String = default_xcaddy_url,
+    xcaddy_version: String = default_xcaddy_version,
+    target_dir: Path = default_target_dir,
+    progress: Progress = new Progress,
+    force: Boolean = false
+  ): Unit = {
+    val platform = Isabelle_Platform.local.ISABELLE_PLATFORM(windows = true, apple = true)
+
+
+    /* component directory */
+
+    val component_dir =
+      Components.Directory(target_dir + Path.basic("caddy-" + caddy_version))
+        .create(permissive = true)
+
+    progress.echo("Component directory " + component_dir)
+
+    component_dir.write_settings("""
+ISABELLE_CADDY_HOME="$COMPONENT"
+
+if [ -n "$ISABELLE_WINDOWS_PLATFORM64" -a -d "$ISABELLE_CADDY_HOME/$ISABELLE_WINDOWS_PLATFORM64" ]; then
+  ISABELLE_CADDY="$ISABELLE_CADDY_HOME/$ISABELLE_WINDOWS_PLATFORM64/caddy.exe"
+elif [ -n "$ISABELLE_APPLE_PLATFORM64" -a -d "$ISABELLE_CADDY_HOME/$ISABELLE_APPLE_PLATFORM64" ]; then
+  ISABELLE_CADDY="$ISABELLE_CADDY_HOME/$ISABELLE_APPLE_PLATFORM64/caddy"
+elif [ -d "$ISABELLE_CADDY_HOME/$ISABELLE_PLATFORM64" ]; then
+  ISABELLE_CADDY="$ISABELLE_CADDY_HOME/$ISABELLE_PLATFORM64/caddy"
+fi
+""")
+
+    for (old <- proper_string(Isabelle_System.getenv("ISABELLE_CADDY_HOME"))) {
+      Components.update_components(false, Path.explode(old))
+    }
+
+    Components.update_components(true, component_dir.path)
+
+
+    /* download and setup */
+
+    Isabelle_System.with_tmp_dir("tmp") { tmp_dir =>
+      val platform_info: Platform_Info =
+        all_platforms.find(_.platform == platform)
+          .getOrElse(error("Bad platform " + quote(platform)))
+
+      val platform_dir = component_dir.path + platform_info.path
+      if (platform_dir.is_dir && !force) {
+        progress.echo_warning("Platform " + platform + " already installed")
+      }
+      else {
+        progress.echo("Platform " + platform + " ...")
+        progress.expose_interrupt()
+
+        Isabelle_System.make_directory(platform_dir)
+
+        val xcaddy_dir = Isabelle_System.make_directory(tmp_dir + Path.explode("xcaddy"))
+        val xcaddy_download = platform_info.xcaddy_download(xcaddy_url, xcaddy_version)
+
+        val xcaddy_archive_name =
+          Url.get_base_name(xcaddy_download) getOrElse
+            error("Malformed download URL " + quote(xcaddy_download))
+        val xcaddy_archive_path = tmp_dir + Path.basic(xcaddy_archive_name)
+
+        Isabelle_System.download_file(xcaddy_download, xcaddy_archive_path)
+        Isabelle_System.extract(xcaddy_archive_path, xcaddy_dir)
+
+        progress.echo("Building caddy " + caddy_version)
+        progress.bash(
+          Library.make_lines(
+            "set -e",
+            "xcaddy/xcaddy build v" + Bash.string(caddy_version) +
+              Word.explode(caddy_modules).map(s => " --with " + Bash.string(s)).mkString,
+            "./caddy list-modules"),
+          cwd = tmp_dir, echo = progress.verbose).check
+
+        Isabelle_System.copy_file(tmp_dir + Path.explode("caddy").platform_exe, platform_dir)
+      }
+    }
+
+    File.find_files(component_dir.path.file, pred = file => File.is_exe(file.getName)).
+      foreach(file => File.set_executable(File.path(file)))
+
+
+    /* README */
+
+    File.write(component_dir.README,
+      """This installation of Caddy has been produced via "isabelle caddy_setup".
+
+
+        Makarius
+        """ + Date.Format.date(Date.now()) + "\n")
+  }
+
+
+  /* Isabelle tool wrapper */
+
+  val isabelle_tool =
+    Isabelle_Tool("caddy_setup", "dynamic setup of Caddy component", Scala_Project.here,
+      { args =>
+        var target_dir = default_target_dir
+        var xcaddy_url = default_xcaddy_url
+        var xcaddy_version = default_xcaddy_version
+        var caddy_modules = default_caddy_modules
+        var caddy_version = default_caddy_version
+        var force = false
+        var verbose = false
+
+        val getopts = Getopts("""
+Usage: isabelle caddy_setup [OPTIONS]
+
+  Options are:
+    -D DIR       target directory (default ".")
+    -N MODULES   non-standard modules for caddy
+                 (default: ISABELLE_CADDY_SETUP_MODULES="""" + default_caddy_modules + """")
+    -U URL       download URL for xcaddy (default: """" + default_xcaddy_url + """")
+    -V VERSION   version for caddy
+                 (default: ISABELLE_CADDY_SETUP_VERSION="""" + default_caddy_version + """")
+    -W VERSION   version for xcaddy (default: """" + default_xcaddy_version + """")
+    -f           force fresh installation of specified platforms
+    -v           verbose
+
+  Build the Caddy webserver via xcaddy and configure it as Isabelle
+  component. See also https://github.com/caddyserver/xcaddy""",
+          "D:" -> (arg => target_dir = Path.explode(arg)),
+          "N:" -> (arg => caddy_modules = arg),
+          "U:" -> (arg => xcaddy_url = arg),
+          "V:" -> (arg => caddy_version = arg),
+          "W:" -> (arg => xcaddy_version = arg),
+          "f" -> (_ => force = true),
+          "v" -> (_ => verbose = true))
+
+        val more_args = getopts(args)
+        if (more_args.nonEmpty) getopts.usage()
+
+        val progress = new Console_Progress(verbose = verbose)
+
+        caddy_setup(caddy_version = caddy_version, caddy_modules = caddy_modules,
+          xcaddy_url = xcaddy_url, xcaddy_version = xcaddy_version, target_dir = target_dir,
+          progress = progress, force = force)
+      })
+}
+
+class Caddy_Setup extends Setup_Tool("caddy_setup", "ISABELLE_CADDY_SETUP") {
+  override val test_file: Path = Path.explode("lib/Tools/caddy")
+}