diff --git a/src/Pure/Admin/build_cygwin.scala b/src/Pure/Admin/build_cygwin.scala --- a/src/Pure/Admin/build_cygwin.scala +++ b/src/Pure/Admin/build_cygwin.scala @@ -1,96 +1,96 @@ /* Title: Pure/Admin/build_cygwin.scala Author: Makarius Produce pre-canned Cygwin distribution for Isabelle. */ package isabelle object Build_Cygwin { val default_mirror: String = "https://isabelle.sketis.net/cygwin_2022" val packages: List[String] = - List("curl", "libgmp-devel", "nano", "openssh", "rsync", "unzip") + List("curl", "libgmp-devel", "nano", "openssh", "rsync") def build_cygwin( target_dir: Path = Path.current, mirror: String = default_mirror, more_packages: List[String] = Nil, progress: Progress = new Progress ): Unit = { require(Platform.is_windows, "Windows platform expected") Isabelle_System.with_tmp_dir("cygwin") { tmp_dir => val cygwin = tmp_dir + Path.explode("cygwin") val cygwin_etc = cygwin + Path.explode("etc") val cygwin_isabelle = Isabelle_System.make_directory(cygwin + Path.explode("isabelle")) val cygwin_exe_name = mirror + "/setup-x86_64.exe" val cygwin_exe = cygwin_isabelle + Path.explode("cygwin.exe") Bytes.write(cygwin_exe, try { Bytes.read(Url(cygwin_exe_name)) } catch { case ERROR(_) => error("Failed to download " + quote(cygwin_exe_name)) }) File.write(cygwin_isabelle + Path.explode("cygwin_mirror"), mirror) File.set_executable(cygwin_exe, true) Isabelle_System.bash(File.bash_path(cygwin_exe) + " -h /dev/null").check val res = progress.bash( File.bash_path(cygwin_exe) + " --site " + Bash.string(mirror) + " --no-verify" + " --local-package-dir 'C:\\temp'" + " --root " + File.bash_platform_path(cygwin) + " --packages " + quote((packages ::: more_packages).mkString(",")) + " --no-shortcuts --no-startmenu --no-desktop --quiet-mode", echo = true) if (!res.ok || !cygwin_etc.is_dir) error("Failed") for (name <- List("hosts", "protocols", "services", "networks", "passwd", "group")) (cygwin_etc + Path.explode(name)).file.delete (cygwin + Path.explode("Cygwin.bat")).file.delete val archive = target_dir + Path.explode("cygwin-" + Date.Format.alt_date(Date.now()) + ".tar.gz") Isabelle_System.gnutar("-czf " + File.bash_path(archive) + " cygwin", dir = tmp_dir).check } } /* Isabelle tool wrapper */ val isabelle_tool = Isabelle_Tool("build_cygwin", "produce pre-canned Cygwin distribution for Isabelle", Scala_Project.here, { args => var target_dir = Path.current var mirror = default_mirror var more_packages: List[String] = Nil val getopts = Getopts(""" Usage: isabelle build_cygwin [OPTIONS] Options are: -D DIR target directory (default ".") -R MIRROR Cygwin mirror site (default """ + quote(default_mirror) + """) -p NAME additional Cygwin package Produce pre-canned Cygwin distribution for Isabelle: this requires Windows administrator mode. """, "D:" -> (arg => target_dir = Path.explode(arg)), "R:" -> (arg => mirror = arg), "p:" -> (arg => more_packages ::= arg)) val more_args = getopts(args) if (more_args.nonEmpty) getopts.usage() val progress = new Console_Progress() build_cygwin(target_dir = target_dir, mirror = mirror, more_packages = more_packages, progress = progress) }) } diff --git a/src/Pure/Tools/build_docker.scala b/src/Pure/Tools/build_docker.scala --- a/src/Pure/Tools/build_docker.scala +++ b/src/Pure/Tools/build_docker.scala @@ -1,177 +1,177 @@ /* Title: Pure/Tools/build_docker.scala Author: Makarius Build docker image from Isabelle application bundle for Linux. */ package isabelle object Build_Docker { private val default_base = "ubuntu:22.04" private val default_work_dir = Path.current private lazy val default_logic = Isabelle_System.getenv("ISABELLE_LOGIC") private val Isabelle_Name = """^.*?(Isabelle[^/\\:]+)_linux(?:_arm)?\.tar\.gz$""".r val packages: List[String] = - List("curl", "less", "libfontconfig1", "libgomp1", "openssh-client", "pwgen", "rsync", "unzip") + List("curl", "less", "libfontconfig1", "libgomp1", "openssh-client", "pwgen", "rsync") val package_collections: Map[String, List[String]] = Map("X11" -> List("libx11-6", "libxext6", "libxrender1", "libxtst6", "libxi6"), "latex" -> List( "texlive-bibtex-extra", "texlive-fonts-extra", "texlive-font-utils", "texlive-latex-extra", "texlive-science")) def all_packages: List[String] = packages ::: package_collections.valuesIterator.flatten.toList def build_docker(progress: Progress, app_archive: String, base: String = default_base, work_dir: Path = default_work_dir, logic: String = default_logic, no_build: Boolean = false, entrypoint: Boolean = false, output: Option[Path] = None, more_packages: List[String] = Nil, tag: String = "", verbose: Boolean = false ): Unit = { val isabelle_name = app_archive match { case Isabelle_Name(name) => name case _ => error("Cannot determine Isabelle distribution name from " + app_archive) } val is_remote = Url.is_wellformed(app_archive) val dockerfile = """## Dockerfile for """ + isabelle_name + """ FROM """ + base + """ SHELL ["/bin/bash", "-c"] # packages ENV DEBIAN_FRONTEND=noninteractive RUN apt-get -y update && \ apt-get install -y """ + Bash.strings(packages ::: more_packages) + """ && \ apt-get clean # user RUN useradd -m isabelle && (echo isabelle:isabelle | chpasswd) USER isabelle # Isabelle WORKDIR /home/isabelle """ + (if (is_remote) "RUN curl --fail --silent " + Bash.string(app_archive) + " > Isabelle.tar.gz" else "COPY Isabelle.tar.gz .") + """ RUN tar xzf Isabelle.tar.gz && \ mv """ + isabelle_name + """ Isabelle && \ sed -i -e 's,ISABELLE_HOME_USER=.*,ISABELLE_HOME_USER="\$USER_HOME/.isabelle",g;' Isabelle/etc/settings && \ sed -i -e 's,ISABELLE_LOGIC=.*,ISABELLE_LOGIC=""" + logic + """,g;' Isabelle/etc/settings && \ Isabelle/bin/isabelle build -o system_heaps -b """ + logic + """ && \ rm Isabelle.tar.gz""" + (if (entrypoint) """ ENTRYPOINT ["Isabelle/bin/isabelle"] """ else "") for (path <- output) { progress.echo("Dockerfile: " + path.absolute) File.write(path, dockerfile) } if (!no_build) { Isabelle_System.make_directory(work_dir) progress.echo("Docker working directory: " + work_dir.absolute) Isabelle_System.with_tmp_dir("docker_build", base_dir = work_dir.file) { tmp_dir => progress.echo("Docker temporary directory: " + tmp_dir.absolute) File.write(tmp_dir + Path.explode("Dockerfile"), dockerfile) if (is_remote) { if (!Url.is_readable(app_archive)) error("Cannot access remote archive " + app_archive) } else { Isabelle_System.copy_file(Path.explode(app_archive), tmp_dir + Path.explode("Isabelle.tar.gz")) } val quiet_option = if (verbose) "" else " -q" val tag_option = if (tag == "") "" else " -t " + Bash.string(tag) progress.bash("docker build" + quiet_option + tag_option + " " + File.bash_path(tmp_dir), echo = true).check } } } /* Isabelle tool wrapper */ val isabelle_tool = Isabelle_Tool("build_docker", "build Isabelle docker image", Scala_Project.here, { args => var base = default_base var entrypoint = false var work_dir = default_work_dir var logic = default_logic var no_build = false var output: Option[Path] = None var more_packages: List[String] = Nil var verbose = false var tag = "" val getopts = Getopts(""" Usage: isabelle build_docker [OPTIONS] APP_ARCHIVE Options are: -B NAME base image (default """ + quote(default_base) + """) -E set Isabelle/bin/isabelle as entrypoint -P NAME additional Ubuntu package collection (""" + package_collections.keySet.toList.sorted.map(quote(_)).mkString(", ") + """) -W DIR working directory that is accessible to docker, potentially via snap (default: """ + default_work_dir + """) -l NAME default logic (default ISABELLE_LOGIC=""" + quote(default_logic) + """) -n no docker build -o FILE output generated Dockerfile -p NAME additional Ubuntu package -t TAG docker build tag -v verbose Build Isabelle docker image with default logic image, using a standard Isabelle application archive for Linux (local file or remote URL). """, "B:" -> (arg => base = arg), "E" -> (_ => entrypoint = true), "P:" -> (arg => package_collections.get(arg) match { case Some(ps) => more_packages :::= ps case None => error("Unknown package collection " + quote(arg)) }), "W:" -> (arg => work_dir = Path.explode(arg)), "l:" -> (arg => logic = arg), "n" -> (_ => no_build = true), "o:" -> (arg => output = Some(Path.explode(arg))), "p:" -> (arg => more_packages ::= arg), "t:" -> (arg => tag = arg), "v" -> (_ => verbose = true)) val more_args = getopts(args) val app_archive = more_args match { case List(arg) => arg case _ => getopts.usage() } build_docker(new Console_Progress(), app_archive, base = base, work_dir = work_dir, logic = logic, no_build = no_build, entrypoint = entrypoint, output = output, more_packages = more_packages, tag = tag, verbose = verbose) }) }