diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 00000000..82c2e515 --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,3 @@ +profile = conventional +version = 0.24.1 +ocaml-version = 4.08 diff --git a/CHANGES.md b/CHANGES.md index ccc4702c..0c82adc6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,15 @@ unreleased ---------- +- Bump to OCaml 4.08 and remove dependencies on result and rresult (@MisterDA #106) +- Wrap libraries: + + `Dockerfile_gen` from the `dockerfile-cmd` package becomes `Dockerfile_cmd.Gen`; + + `Dockerfile_distro`, `Dockerfile_linux`, `Dockerfile_windows` from the + `dockerfile_opam` package respectively become `Dockerfile_opam.Distro`, + `Dockerfile_opam.Linux`, `Dockerfile_opam.Windows`. (@MisterDA #106) +- Generate opam images using BuildKit 1.4 syntax for Dockerfiles. (@MisterDA #105) - Support BuildKit 1.4 syntax of here-documents in `COPY` instructions. (@MisterDA #99) - Support BuildKit 1.4 `--link` flag in `ADD` and `COPY` instructions. (@MisterDA #99) -- Generate opam images using BuildKit 1.4 syntax for Dockerfiles. (@MisterDA #105) v8.0.0 2022-07-27 Sydney ------------------------ diff --git a/dockerfile-cmd.opam b/dockerfile-cmd.opam index 1be93664..482836ff 100644 --- a/dockerfile-cmd.opam +++ b/dockerfile-cmd.opam @@ -1,32 +1,62 @@ +# This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "Dockerfile eDSL - generation support" +synopsis: "Dockerfile eDSL -- generation support" description: """ This library provides a typed OCaml interface to generating Dockerfiles programmatically without having to resort to lots of shell scripting and awk/sed-style assembly. This sublibrary has support functions for generating arrays of Dockerfiles -programmatically.""" -maintainer: "Anil Madhavapeddy " -authors: "Anil Madhavapeddy " +programmatically. +""" +maintainer: [ + "Anil Madhavapeddy " + "Antonin Décimo " + "David Allsopp " + "Kate " + "Thomas Leonard " + "Tim McGilchrist " +] +authors: [ + "Anil Madhavapeddy" + "Anton Kochkov" + "Antonin Décimo" + "David Allsopp" + "Ewan Mellor" + "Kate Deplaix" + "Louis Gesbert" + "Mark Elvers" + "Thomas Leonard" + "Tim McGilchrist" +] license: "ISC" tags: ["org:mirage" "org:ocamllabs"] homepage: "https://github.com/ocurrent/ocaml-dockerfile" -doc: "https://ocurrent.github.io/ocaml-dockerfile/doc" +doc: "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile-cmd/" bug-reports: "https://github.com/ocurrent/ocaml-dockerfile/issues" depends: [ - "ocaml" {>= "4.02.3"} - "dune" {>= "2.0.0"} - "dockerfile-opam" {= version} + "dune" {>= "3.0"} + "bos" "cmdliner" - "fmt" + "dockerfile-opam" {= version} + "fmt" {>= "0.8.7"} "logs" - "bos" - "result" "ppx_sexp_conv" {>= "v0.9.0"} + "sexplib" + "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} - ["dune" "build" "-p" name "-j" jobs] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] ] dev-repo: "git+https://github.com/ocurrent/ocaml-dockerfile.git" diff --git a/dockerfile-opam.opam b/dockerfile-opam.opam index c4ef79bf..acdcc0ff 100644 --- a/dockerfile-opam.opam +++ b/dockerfile-opam.opam @@ -1,3 +1,4 @@ +# This file is generated by dune, edit dune-project instead opam-version: "2.0" synopsis: "Dockerfile eDSL -- opam support" description: """ @@ -5,31 +6,56 @@ This library provides a typed OCaml interface to generating Dockerfiles programmatically without having to resort to lots of shell scripting and awk/sed-style assembly. -The opam subpackage provides opam and Linux-specific distribution -support for generating dockerfiles.""" -maintainer: "Anil Madhavapeddy " -authors: [ +The opam subpackage provides opam and Linux-specific distribution support +for generating dockerfiles. +""" +maintainer: [ "Anil Madhavapeddy " "Antonin Décimo " + "David Allsopp " + "Kate " + "Thomas Leonard " + "Tim McGilchrist " +] +authors: [ + "Anil Madhavapeddy" + "Anton Kochkov" + "Antonin Décimo" + "David Allsopp" + "Ewan Mellor" + "Kate Deplaix" + "Louis Gesbert" + "Mark Elvers" + "Thomas Leonard" + "Tim McGilchrist" ] license: "ISC" tags: ["org:mirage" "org:ocamllabs"] homepage: "https://github.com/ocurrent/ocaml-dockerfile" -doc: "https://ocurrent.github.io/ocaml-dockerfile/doc" +doc: "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile-opam/" bug-reports: "https://github.com/ocurrent/ocaml-dockerfile/issues" depends: [ - "ocaml" {>= "4.02.3"} - "dune" {>= "2.0.0"} - "dockerfile" {= version} - "ocaml-version" {>= "3.5.0"} - "cmdliner" + "dune" {>= "3.0"} "astring" + "dockerfile" {= version} + "fmt" {>= "0.8.7"} + "ocaml-version" {>= "3.2.0"} "ppx_sexp_conv" {>= "v0.9.0"} "sexplib" - "fmt" + "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} - ["dune" "build" "-p" name "-j" jobs] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] ] dev-repo: "git+https://github.com/ocurrent/ocaml-dockerfile.git" diff --git a/dockerfile.opam b/dockerfile.opam index a3510112..a3e54ce3 100644 --- a/dockerfile.opam +++ b/dockerfile.opam @@ -1,25 +1,56 @@ +# This file is generated by dune, edit dune-project instead opam-version: "2.0" synopsis: "Dockerfile eDSL in OCaml" description: """ This library provides a typed OCaml interface to generating Dockerfiles programmatically without having to resort to lots of shell scripting and -awk/sed-style assembly.""" -maintainer: "Anil Madhavapeddy " -authors: "Anil Madhavapeddy " +awk/sed-style assembly. +""" +maintainer: [ + "Anil Madhavapeddy " + "Antonin Décimo " + "David Allsopp " + "Kate " + "Thomas Leonard " + "Tim McGilchrist " +] +authors: [ + "Anil Madhavapeddy" + "Anton Kochkov" + "Antonin Décimo" + "David Allsopp" + "Ewan Mellor" + "Kate Deplaix" + "Louis Gesbert" + "Mark Elvers" + "Thomas Leonard" + "Tim McGilchrist" +] license: "ISC" tags: ["org:mirage" "org:ocamllabs"] homepage: "https://github.com/ocurrent/ocaml-dockerfile" -doc: "https://ocurrent.github.io/ocaml-dockerfile/doc" +doc: "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile/" bug-reports: "https://github.com/ocurrent/ocaml-dockerfile/issues" depends: [ - "ocaml" {>= "4.02.3"} - "dune" {>= "2.0.0"} + "dune" {>= "3.0"} + "ocaml" {>= "4.08"} + "fmt" {>= "0.8.7"} "ppx_sexp_conv" {>= "v0.9.0"} "sexplib" - "fmt" + "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} - ["dune" "build" "-p" name "-j" jobs] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] ] dev-repo: "git+https://github.com/ocurrent/ocaml-dockerfile.git" diff --git a/dune-project b/dune-project index a1922af3..a7107086 100644 --- a/dune-project +++ b/dune-project @@ -1,5 +1,86 @@ -(lang dune 2.0) - +(lang dune 3.0) (name dockerfile) -(formatting disabled) +(generate_opam_files true) + +(source (github ocurrent/ocaml-dockerfile)) +(license "ISC") + +(authors + "Anil Madhavapeddy" + "Anton Kochkov" + "Antonin Décimo" + "David Allsopp" + "Ewan Mellor" + "Kate Deplaix" + "Louis Gesbert" + "Mark Elvers" + "Thomas Leonard" + "Tim McGilchrist") + +(maintainers + "Anil Madhavapeddy " + "Antonin Décimo " + "David Allsopp " + "Kate " + "Thomas Leonard " + "Tim McGilchrist ") + +(package + (name dockerfile) + (synopsis "Dockerfile eDSL in OCaml") + (description +"\| This library provides a typed OCaml interface to generating Dockerfiles +"\| programmatically without having to resort to lots of shell scripting and +"\| awk/sed-style assembly. + ) + (depends + (ocaml (>= "4.08")) + (fmt (>= "0.8.7")) + (ppx_sexp_conv (>= "v0.9.0")) + sexplib) + (documentation "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile/") + (tags ("org:mirage" "org:ocamllabs"))) + +(package + (name dockerfile-cmd) + (synopsis "Dockerfile eDSL -- generation support") + (description +"\| This library provides a typed OCaml interface to generating Dockerfiles +"\| programmatically without having to resort to lots of shell scripting and +"\| awk/sed-style assembly. +"\| +"\| This sublibrary has support functions for generating arrays of Dockerfiles +"\| programmatically. + ) + (depends + bos + cmdliner + (dockerfile-opam (= :version)) + (fmt (>= "0.8.7")) + logs + (ppx_sexp_conv (>= "v0.9.0")) + sexplib) + (documentation "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile-cmd/") + (tags ("org:mirage" "org:ocamllabs"))) + +(package + (name dockerfile-opam) + (synopsis "Dockerfile eDSL -- opam support") + (description +"\| This library provides a typed OCaml interface to generating Dockerfiles +"\| programmatically without having to resort to lots of shell scripting and +"\| awk/sed-style assembly. +"\| +"\| The opam subpackage provides opam and Linux-specific distribution support +"\| for generating dockerfiles. + ) + (depends + astring + (dockerfile (= :version)) + (fmt (>= "0.8.7")) + (ocaml-version (>= "3.2.0")) + (ppx_sexp_conv (>= "v0.9.0")) + sexplib) + (documentation "https://ocurrent.github.io/ocaml-dockerfile/doc/dockerfile-opam/") + (tags ("org:mirage" "org:ocamllabs"))) diff --git a/src-cmd/dockerfile_cmd.ml b/src-cmd/dockerfile_cmd.ml index 8c837a62..3c2de5f1 100644 --- a/src-cmd/dockerfile_cmd.ml +++ b/src-cmd/dockerfile_cmd.ml @@ -16,47 +16,52 @@ *) open Sexplib.Conv -open Rresult open Bos open Astring -open R.Infix module OC = OS.Cmd +let ( >>= ) = Result.bind + let rec iter fn l = - match l with - | hd::tl -> fn hd >>= fun () -> iter fn tl - | [] -> Ok () + match l with hd :: tl -> fn hd >>= fun () -> iter fn tl | [] -> Ok () let map fn l = - List.map fn l |> - List.fold_left (fun acc b -> - match acc, b with - | Ok acc, Ok v -> Ok (v :: acc) - | Ok _acc, Error v -> Error v - | Error _ as e, _ -> e - ) (Ok []) |> function + List.map fn l + |> List.fold_left + (fun acc b -> + match (acc, b) with + | Ok acc, Ok v -> Ok (v :: acc) + | Ok _acc, Error v -> Error v + | (Error _ as e), _ -> e) + (Ok []) + |> function | Ok v -> Ok (List.rev v) | e -> e -type cmd_log = { - command: string; - stdout: string; - success: bool; - status: [ `Signaled of int | `Exited of int ] -} [@@deriving sexp] +module Gen = Gen -let run_log ?(ok_to_fail=true) ?env log_dir name cmd = +type cmd_log = { + command : string; + stdout : string; + success : bool; + status : [ `Signaled of int | `Exited of int ]; +} +[@@deriving sexp] + +let run_log ?(ok_to_fail = true) ?env log_dir name cmd = let command = Cmd.to_string cmd in - OS.Cmd.(run_out ?env ~err:err_run_out) cmd |> - OS.Cmd.out_string >>= fun (stdout, (_,status)) -> + OS.Cmd.(run_out ?env ~err:err_run_out) cmd |> OS.Cmd.out_string + >>= fun (stdout, (_, status)) -> let success = status = `Exited 0 in let cmd_log = { command; stdout; success; status } in let path = Fpath.(log_dir / (name ^ ".sxp")) in - OS.File.write path (Sexplib.Sexp.to_string_hum (sexp_of_cmd_log cmd_log)) >>= fun () -> + OS.File.write path (Sexplib.Sexp.to_string_hum (sexp_of_cmd_log cmd_log)) + >>= fun () -> match status with - |`Signaled n -> if ok_to_fail then Ok () else R.error_msg (Fmt.str "Signal %d" n) - |`Exited 0 -> Ok () - |`Exited code -> if ok_to_fail then Ok () else R.error_msg (Fmt.str "Exit code %d" code) + | `Signaled n -> if ok_to_fail then Ok () else Fmt.error_msg "Signal %d" n + | `Exited 0 -> Ok () + | `Exited code -> + if ok_to_fail then Ok () else Fmt.error_msg "Exit code %d" code (** Docker *) module Docker = struct @@ -64,56 +69,69 @@ module Docker = struct let info = Cmd.(bin % "info") let exists () = - OS.Cmd.run_out info |> OS.Cmd.out_string |> R.is_ok |> - function - | true -> Logs.info (fun l -> l "Docker is running"); true - | false -> Logs.err (fun l -> l "Docker not running"); false - - let build_cmd ?(squash=false) ?(pull=true) ?(cache=true) ?dockerfile ?tag path = + match OS.Cmd.run_out info |> OS.Cmd.out_string with + | Ok _ -> + Logs.info (fun l -> l "Docker is running"); + true + | Error (`Msg msg) -> + Logs.err (fun l -> l "Docker not running: %s" msg); + false + + let build_cmd ?(squash = false) ?(pull = true) ?(cache = true) ?dockerfile + ?tag path = let open Cmd in let cache = if cache then empty else v "--no-cache" in let pull = if pull then v "--pull" else empty in let squash = if squash then v "--squash" else empty in - let dfile = match dockerfile with None -> empty | Some d -> v "-f" % p d in + let dfile = + match dockerfile with None -> empty | Some d -> v "-f" % p d + in let tag = match tag with None -> empty | Some t -> v "-t" % t in - bin % "build" %% tag %% cache %% pull %% squash %% dfile % p path - - let volume_cmd = - Cmd.(bin % "volume") + bin % "build" %% tag %% cache %% pull %% squash %% dfile % p path - let push_cmd tag = - Cmd.(bin % "push" % tag) + let volume_cmd = Cmd.(bin % "volume") + let push_cmd tag = Cmd.(bin % "push" % tag) (* Find the image id that we just built *) let build_id log = - let rec find_id = - function - | hd::tl when String.is_prefix ~affix:"Successfully tagged " hd -> find_id tl - | hd::_ when String.is_prefix ~affix:"Successfully built " hd -> begin - match String.cut ~sep:"Successfully built " hd with - | Some ("", id) -> R.ok id - | Some _ -> R.error_msg "Unexpected internal error in build_id" - | None -> R.error_msg "Malformed successfully built log" - end - | _hd::_tl -> R.error_msg "Unexpected lines at end of log" - | [] -> R.error_msg "Unable to find container id in log" in + let rec find_id = function + | hd :: tl when String.is_prefix ~affix:"Successfully tagged " hd -> + find_id tl + | hd :: _ when String.is_prefix ~affix:"Successfully built " hd -> ( + match String.cut ~sep:"Successfully built " hd with + | Some ("", id) -> Ok id + | Some _ -> Fmt.error_msg "Unexpected internal error in build_id" + | None -> Fmt.error_msg "Malformed successfully built log") + | _hd :: _tl -> Fmt.error_msg "Unexpected lines at end of log" + | [] -> Fmt.error_msg "Unable to find container id in log" + in OS.File.read_lines log >>= fun lines -> - List.rev lines |> fun lines -> - find_id lines + List.rev lines |> fun lines -> find_id lines let manifest_push_cli ~platforms ~template ~target = let platforms = String.concat ~sep:"," platforms in - Cmd.(v "manifest-tool" % "push" % "from-args" % "--platforms" % platforms - % "--template" % template % "--target" % target) + Cmd.( + v "manifest-tool" % "push" % "from-args" % "--platforms" % platforms + % "--template" % template % "--target" % target) let manifest_push_file file = - Cmd.(v "manifest-tool" % "push" % "from-spec" % p file) + Cmd.(v "manifest-tool" % "push" % "from-spec" % p file) - let run_cmd ?(mounts=[]) ?(volumes=[]) ?(rm=true) img cmd = + let run_cmd ?(mounts = []) ?(volumes = []) ?(rm = true) img cmd = let rm = if rm then Cmd.(v "--rm") else Cmd.empty in - let mounts = List.map (fun (src,dst) -> ["--mount"; Printf.sprintf "source=%s,destination=%s" src dst]) mounts |> List.flatten |> Cmd.of_list in + let mounts = + List.map + (fun (src, dst) -> + [ "--mount"; Printf.sprintf "source=%s,destination=%s" src dst ]) + mounts + |> List.flatten |> Cmd.of_list + in let vols = - List.map (fun (src,dst) -> ["-v"; Printf.sprintf "%s:%s" src dst]) volumes |> List.flatten |> Cmd.of_list in + List.map + (fun (src, dst) -> [ "-v"; Printf.sprintf "%s:%s" src dst ]) + volumes + |> List.flatten |> Cmd.of_list + in Cmd.(bin % "run" %% rm %% mounts %% vols % img %% cmd) end @@ -123,19 +141,22 @@ module Opam = struct let opam_env ~root ~jobs = OS.Env.current () >>= fun env -> - String.Map.add "OPAMROOT" (Cmd.p root) env |> - String.Map.add "OPAMYES" "1" |> - String.Map.add "OPAMJOBS" (string_of_int jobs) |> fun env -> - R.return env + String.Map.add "OPAMROOT" (Cmd.p root) env + |> String.Map.add "OPAMYES" "1" + |> String.Map.add "OPAMJOBS" (string_of_int jobs) + |> Result.ok end open Cmdliner + let setup_logs () = let setup_log style_renderer level = Fmt_tty.setup_std_outputs ?style_renderer (); Logs.set_level level; - Logs.set_reporter (Logs_fmt.reporter ()) in + Logs.set_reporter (Logs_fmt.reporter ()) + in let global_option_section = "COMMON OPTIONS" in - Term.(const setup_log + Term.( + const setup_log $ Fmt_cli.style_renderer ~docs:global_option_section () $ Logs_cli.level ~docs:global_option_section ()) diff --git a/src-cmd/dockerfile_cmd.mli b/src-cmd/dockerfile_cmd.mli index 1e6522fa..cb1dcbfd 100644 --- a/src-cmd/dockerfile_cmd.mli +++ b/src-cmd/dockerfile_cmd.mli @@ -24,49 +24,53 @@ Feel free to contribute more functions if you need them. *) type cmd_log = { - command: string; - stdout: string; - success: bool; - status: [ `Signaled of int | `Exited of int ] -} [@@deriving sexp] + command : string; + stdout : string; + success : bool; + status : [ `Signaled of int | `Exited of int ]; +} +[@@deriving sexp] (** Results of a command invocation *) val run_log : ?ok_to_fail:bool -> ?env:Bos.OS.Env.t -> Fpath.t -> - string -> Bos.Cmd.t -> (unit, [> Rresult.R.msg ]) result -(** [runlog log_dir name cmd] will run [cmd] with label [name] + string -> + Bos.Cmd.t -> + (unit, [> `Msg of string ]) result +(** [runlog log_dir name cmd] will run [cmd] with label [name] and log the results in [/.sxp]. *) (** Docker command invocation *) module Docker : sig val bin : Bos.Cmd.t - val info : Bos.Cmd.t - val exists : unit -> bool val build_cmd : ?squash:bool -> ?pull:bool -> ?cache:bool -> - ?dockerfile:Fpath.t -> ?tag:string -> Fpath.t -> Bos.Cmd.t + ?dockerfile:Fpath.t -> + ?tag:string -> + Fpath.t -> + Bos.Cmd.t val volume_cmd : Bos.Cmd.t - val push_cmd : string -> Bos.Cmd.t - - val build_id : Fpath.t -> (string, [> Rresult.R.msg ]) result + val build_id : Fpath.t -> (string, [> `Msg of string ]) result val run_cmd : ?mounts:(string * string) list -> ?volumes:(string * string) list -> - ?rm:bool -> string -> Bos.Cmd.t -> Bos.Cmd.t + ?rm:bool -> + string -> + Bos.Cmd.t -> + Bos.Cmd.t val manifest_push_cli : - platforms:string list -> - template:string -> target:string -> Bos.Cmd.t + platforms:string list -> template:string -> target:string -> Bos.Cmd.t val manifest_push_file : Fpath.t -> Bos.Cmd.t end @@ -77,17 +81,18 @@ module Opam : sig val opam_env : root:Fpath.t -> - jobs:int -> (string Astring.String.map, [> Rresult.R.msg ]) result - + jobs:int -> + (string Astring.String.map, [> `Msg of string ]) result end (** {2 Utility functions} *) -val setup_logs : unit -> unit Cmdliner.Term.t +val setup_logs : unit -> unit Cmdliner.Term.t (** [setup_logs ()] initialises a {!Logs} environment. *) val iter : ('a -> (unit, 'b) result) -> 'a list -> (unit, 'b) result - val map : ('a -> ('b, 'c) result) -> 'a list -> ('b list, 'c) result +(** {2 Generate Dockerfiles} *) +module Gen = Gen diff --git a/src-cmd/dockerfile_gen.ml b/src-cmd/dockerfile_gen.ml deleted file mode 100644 index 46a6091e..00000000 --- a/src-cmd/dockerfile_gen.ml +++ /dev/null @@ -1,73 +0,0 @@ -(* - * Copyright (c) 2016-2017 Anil Madhavapeddy - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - *) - -open Dockerfile -open Bos -open Rresult -open R.Infix -module U = Dockerfile_cmd - -let write_dockerfile ~crunch file dfile = - Logs.debug (fun l -> l "Writing Dockerfile to %a" Fpath.pp file); - (if crunch then Dockerfile.crunch dfile else dfile) |> - string_of_t |> OS.File.write file - -let generate_dockerfile ?(fname="Dockerfile") ?(crunch=true) output_dir d = - let file = Fpath.(output_dir / fname) in - Logs.info (fun l -> l "Generating: %a" Fpath.pp file); - OS.Dir.create ~path:true output_dir >>= fun _ -> - write_dockerfile ~crunch file d - -let generate_dockerfiles_in_directories ?(crunch=true) output_dir = - U.iter (fun (name, dockerfile) -> - let dir = Fpath.(output_dir / name) in - let file = Fpath.(dir / "Dockerfile") in - Logs.info (fun l -> l "Generating %a" Fpath.pp file); - OS.Dir.create ~path:true output_dir >>= fun _ -> - write_dockerfile ~crunch file dockerfile - ) - -let generate_dockerfiles ?(crunch=true) output_dir = - U.iter (fun (name, dockerfile) -> - let file = Fpath.(output_dir / ("Dockerfile." ^ name)) in - Logs.info (fun l -> l "Generating: %a" Fpath.pp file); - write_dockerfile ~crunch file dockerfile - ) - -let generate_dockerfiles_in_git_branches ?readme ?(crunch=true) output_dir d = - (* TODO move git to dockerfile_cmd *) - let git = Cmd.(v "git" % "-C" % p output_dir) in - U.iter (fun (name, docker) -> - Logs.info (fun l -> l "Switching to branch %s in %a\n%!" name Fpath.pp output_dir); - OS.Cmd.run (match name with - | "master" -> Cmd.(git % "checkout" % "master") - | name -> Cmd.(git % "checkout" % "-q" % "-B" % name % "master") - ) >>= fun () -> - let file = Fpath.(output_dir / "Dockerfile") in - write_dockerfile ~crunch file docker >>= fun () -> - begin match readme with - | None -> Ok () - | Some r -> - OS.File.write Fpath.(output_dir / "README.md") r >>= fun () -> - Cmd.(git % "add" % "README.md") |> OS.Cmd.run - end >>= fun () -> - Cmd.(git % "add" % "Dockerfile") |> OS.Cmd.run >>= fun () -> - let msg = Fmt.str "update %s Dockerfile" name in - Cmd.(git % "commit" % "-q" % "-m" % msg % "-a") |> OS.Cmd.run_status >>= fun _ -> - Ok () - ) d >>= fun () -> - Cmd.(git % "checkout" % "-q" % "master") |> OS.Cmd.run diff --git a/src-cmd/dune b/src-cmd/dune index bef43bb0..4da5a395 100644 --- a/src-cmd/dune +++ b/src-cmd/dune @@ -2,10 +2,9 @@ (name dockerfile_cmd) (public_name dockerfile-cmd) (synopsis - "Utility functions to generate Dockerfiles and execute Docker commands") - (wrapped false) + "Utility functions to generate Dockerfiles and execute Docker commands") (preprocess (per_module ((pps ppx_sexp_conv) dockerfile_cmd))) - (libraries dockerfile cmdliner bos fmt.tty logs.cli fmt.cli logs.fmt result)) + (libraries dockerfile cmdliner bos fmt.tty logs.cli fmt.cli logs.fmt)) diff --git a/src-cmd/gen.ml b/src-cmd/gen.ml new file mode 100644 index 00000000..20895192 --- /dev/null +++ b/src-cmd/gen.ml @@ -0,0 +1,76 @@ +(* + * Copyright (c) 2016-2017 Anil Madhavapeddy + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *) + +open Dockerfile +open Bos + +let ( >>= ) = Result.bind + +let rec iter fn l = + match l with hd :: tl -> fn hd >>= fun () -> iter fn tl | [] -> Ok () + +let write_dockerfile ~crunch file dfile = + Logs.debug (fun l -> l "Writing Dockerfile to %a" Fpath.pp file); + (if crunch then Dockerfile.crunch dfile else dfile) + |> string_of_t |> OS.File.write file + +let generate_dockerfile ?(fname = "Dockerfile") ?(crunch = true) output_dir d = + let file = Fpath.(output_dir / fname) in + Logs.info (fun l -> l "Generating: %a" Fpath.pp file); + OS.Dir.create ~path:true output_dir >>= fun _ -> + write_dockerfile ~crunch file d + +let generate_dockerfiles_in_directories ?(crunch = true) output_dir = + iter (fun (name, dockerfile) -> + let dir = Fpath.(output_dir / name) in + let file = Fpath.(dir / "Dockerfile") in + Logs.info (fun l -> l "Generating %a" Fpath.pp file); + OS.Dir.create ~path:true output_dir >>= fun _ -> + write_dockerfile ~crunch file dockerfile) + +let generate_dockerfiles ?(crunch = true) output_dir = + iter (fun (name, dockerfile) -> + let file = Fpath.(output_dir / ("Dockerfile." ^ name)) in + Logs.info (fun l -> l "Generating: %a" Fpath.pp file); + write_dockerfile ~crunch file dockerfile) + +let generate_dockerfiles_in_git_branches ?readme ?(crunch = true) output_dir d = + (* TODO move git to dockerfile_cmd *) + let git = Cmd.(v "git" % "-C" % p output_dir) in + iter + (fun (name, docker) -> + Logs.info (fun l -> + l "Switching to branch %s in %a\n%!" name Fpath.pp output_dir); + OS.Cmd.run + (match name with + | "master" -> Cmd.(git % "checkout" % "master") + | name -> Cmd.(git % "checkout" % "-q" % "-B" % name % "master")) + >>= fun () -> + let file = Fpath.(output_dir / "Dockerfile") in + write_dockerfile ~crunch file docker >>= fun () -> + (match readme with + | None -> Ok () + | Some r -> + OS.File.write Fpath.(output_dir / "README.md") r >>= fun () -> + Cmd.(git % "add" % "README.md") |> OS.Cmd.run) + >>= fun () -> + Cmd.(git % "add" % "Dockerfile") |> OS.Cmd.run >>= fun () -> + let msg = Fmt.str "update %s Dockerfile" name in + Cmd.(git % "commit" % "-q" % "-m" % msg % "-a") |> OS.Cmd.run_status + >>= fun _ -> Ok ()) + d + >>= fun () -> Cmd.(git % "checkout" % "-q" % "master") |> OS.Cmd.run diff --git a/src-cmd/dockerfile_gen.mli b/src-cmd/gen.mli similarity index 80% rename from src-cmd/dockerfile_gen.mli rename to src-cmd/gen.mli index 4056b6ed..bb41aeb4 100644 --- a/src-cmd/dockerfile_gen.mli +++ b/src-cmd/gen.mli @@ -15,7 +15,14 @@ * *) -val generate_dockerfile : ?fname:string -> ?crunch:bool -> Fpath.t -> Dockerfile.t -> (unit, [> Rresult.R.msg ]) Result.result +(** Utility functions to generate Dockerfiles. *) + +val generate_dockerfile : + ?fname:string -> + ?crunch:bool -> + Fpath.t -> + Dockerfile.t -> + (unit, [> `Msg of string ]) result (** [generate_dockerfile output_dir docker] will output Dockerfile inside the [output_dir] subdirectory. @@ -23,8 +30,11 @@ val generate_dockerfile : ?fname:string -> ?crunch:bool -> Fpath.t -> Dockerfile optimisation to reduce the number of layers; disable it if you really want more layers. *) -val generate_dockerfiles : ?crunch:bool -> Fpath.t -> - (string * Dockerfile.t) list -> (unit, [> Rresult.R.msg ]) Result.result +val generate_dockerfiles : + ?crunch:bool -> + Fpath.t -> + (string * Dockerfile.t) list -> + (unit, [> `Msg of string ]) result (** [generate_dockerfiles output_dir (name * docker)] will output a list of Dockerfiles inside the [output_dir/] subdirectory, with each Dockerfile named as [Dockerfile.]. @@ -33,8 +43,11 @@ val generate_dockerfiles : ?crunch:bool -> Fpath.t -> optimisation to reduce the number of layers; disable it if you really want more layers. *) -val generate_dockerfiles_in_directories : ?crunch:bool -> Fpath.t -> - (string * Dockerfile.t) list -> (unit, [> Rresult.R.msg ]) Result.result +val generate_dockerfiles_in_directories : + ?crunch:bool -> + Fpath.t -> + (string * Dockerfile.t) list -> + (unit, [> `Msg of string ]) result (** [generate_dockerfiles_in_directories output_dir (name * docker)] will output a list of Dockerfiles inside the [output_dir/name] subdirectory, with each directory containing the Dockerfile specified by [docker]. @@ -43,8 +56,12 @@ val generate_dockerfiles_in_directories : ?crunch:bool -> Fpath.t -> optimisation to reduce the number of layers; disable it if you really want more layers. *) -val generate_dockerfiles_in_git_branches : ?readme:string -> ?crunch:bool -> - Fpath.t -> (string * Dockerfile.t) list -> (unit, [> Rresult.R.msg ]) Result.result +val generate_dockerfiles_in_git_branches : + ?readme:string -> + ?crunch:bool -> + Fpath.t -> + (string * Dockerfile.t) list -> + (unit, [> `Msg of string ]) result (** [generate_dockerfiles_in_git_branches output_dir (name * docker)] will output a set of git branches in the [output_dir] Git repository. Each branch will be named [name] and contain a single [docker] file. diff --git a/src-opam/distro.ml b/src-opam/distro.ml new file mode 100644 index 00000000..7bdae73e --- /dev/null +++ b/src-opam/distro.ml @@ -0,0 +1,1271 @@ +(* + * Copyright (c) 2016-2017 Anil Madhavapeddy + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *) + +open Astring +(** Distro selection for various OPAM combinations *) + +open Sexplib.Conv + +type win10_release = + [ `V1507 + | `V1511 + | `V1607 + | `V1703 + | `V1709 + | `V1803 + | `V1809 + | `V1903 + | `V1909 + | `V2004 + | `V20H2 + | `V21H1 + | `V21H2 ] +[@@deriving sexp] + +type win10_ltsc = [ `Ltsc2015 | `Ltsc2016 | `Ltsc2019 | `Ltsc2022 ] +[@@deriving sexp] + +type win10_lcu = + [ `LCU + | `LCU20220913 + | `LCU20220809 + | `LCU20220712 + | `LCU20220614 + | `LCU20220510 + | `LCU20220412 + | `LCU20220308 + | `LCU20220208 + | `LCU20220111 + | `LCU20211214 + | `LCU20211109 + | `LCU20211012 + | `LCU20210914 + | `LCU20210810 + | `LCU20210713 + | `LCU20210608 ] +[@@deriving sexp] + +type win_all = [ win10_release | win10_ltsc ] [@@deriving sexp] + +let win10_current_lcu = `LCU20220913 + +type win10_revision = win10_release * win10_lcu option [@@deriving sexp] + +let win10_lcus : ('a * int * win10_release list) list = + [ + (`LCU20220913, 5017316, [ `V21H2 ]); + (`LCU20220913, 5017308, [ `V21H1 ]); + (`LCU20220913, 5017315, [ `V1809 ]); + (`LCU20220913, 5017305, [ `V1607 ]); + (`LCU20220913, 5017327, [ `V1507 ]); + (`LCU20220809, 5016627, [ `V21H2 ]); + (`LCU20220809, 5016616, [ `V20H2; `V21H1 ]); + (`LCU20220809, 5016623, [ `V1809 ]); + (`LCU20220809, 5016622, [ `V1607 ]); + (`LCU20220809, 5016639, [ `V1507 ]); + (`LCU20220712, 5015827, [ `V21H2 ]); + (`LCU20220712, 5015807, [ `V20H2; `V21H1 ]); + (`LCU20220712, 5015811, [ `V1809 ]); + (`LCU20220712, 5015808, [ `V1607 ]); + (`LCU20220712, 5015832, [ `V1507 ]); + (`LCU20220614, 5014678, [ `V21H2 ]); + (`LCU20220614, 5014699, [ `V20H2; `V21H1 ]); + (`LCU20220614, 5014692, [ `V1809 ]); + (`LCU20220614, 5014702, [ `V1607 ]); + (`LCU20220614, 5014710, [ `V1507 ]); + (`LCU20220510, 5013944, [ `V21H2 ]); + (`LCU20220510, 5013942, [ `V20H2; `V21H1 ]); + (`LCU20220510, 5013945, [ `V1909 ]); + (`LCU20220510, 5013941, [ `V1809 ]); + (`LCU20220510, 5013952, [ `V1607 ]); + (`LCU20220510, 5013963, [ `V1507 ]); + (`LCU20220412, 5012604, [ `V21H2 ]); + (`LCU20220412, 5012599, [ `V20H2; `V21H1 ]); + (`LCU20220412, 5012591, [ `V1909 ]); + (`LCU20220412, 5012647, [ `V1809 ]); + (`LCU20220412, 5012596, [ `V1607 ]); + (`LCU20220412, 5012653, [ `V1507 ]); + (`LCU20220308, 5011497, [ `V21H2 ]); + (`LCU20220308, 5011487, [ `V20H2; `V21H1 ]); + (`LCU20220308, 5011485, [ `V1909 ]); + (`LCU20220308, 5011503, [ `V1809 ]); + (`LCU20220308, 5011495, [ `V1607 ]); + (`LCU20220308, 5011491, [ `V1507 ]); + (`LCU20220208, 5010354, [ `V21H2 ]); + (`LCU20220208, 5010342, [ `V20H2; `V21H1 ]); + (`LCU20220208, 5010345, [ `V1909 ]); + (`LCU20220208, 5010351, [ `V1809 ]); + (`LCU20220208, 5010359, [ `V1607 ]); + (`LCU20220208, 5010358, [ `V1507 ]); + (`LCU20220111, 5009555, [ `V21H2 ]); + (`LCU20220111, 5009543, [ `V20H2; `V21H1 ]); + (`LCU20220111, 5009545, [ `V1909 ]); + (`LCU20220111, 5009557, [ `V1809 ]); + (`LCU20220111, 5009546, [ `V1607 ]); + (`LCU20220111, 5009585, [ `V1507 ]); + (`LCU20211214, 5008223, [ `V21H2 ]); + (`LCU20211214, 5008212, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20211214, 5008206, [ `V1909 ]); + (`LCU20211214, 5008218, [ `V1809 ]); + (`LCU20211214, 5008207, [ `V1607 ]); + (`LCU20211214, 5008230, [ `V1507 ]); + (`LCU20211109, 5007205, [ `V21H2 ]); + (`LCU20211109, 5007186, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20211109, 5007189, [ `V1909 ]); + (`LCU20211109, 5007206, [ `V1809 ]); + (`LCU20211109, 5007192, [ `V1607 ]); + (`LCU20211109, 5007207, [ `V1507 ]); + (`LCU20211012, 5006699, [ `V21H2 ]); + (`LCU20211012, 5006670, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20211012, 5006667, [ `V1909 ]); + (`LCU20211012, 5006672, [ `V1809 ]); + (`LCU20211012, 5006669, [ `V1607 ]); + (`LCU20211012, 5006675, [ `V1507 ]); + (`LCU20210914, 5005575, [ `V21H2 ]); + (`LCU20210914, 5005565, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20210914, 5005566, [ `V1909 ]); + (`LCU20210914, 5005568, [ `V1809 ]); + (`LCU20210914, 5005573, [ `V1607 ]); + (`LCU20210914, 5005569, [ `V1507 ]); + (`LCU20210810, 5005039, [ `V21H2 ]); + (`LCU20210810, 5005033, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20210810, 5005031, [ `V1909 ]); + (`LCU20210810, 5005030, [ `V1809 ]); + (`LCU20210810, 5005043, [ `V1607 ]); + (`LCU20210810, 5005040, [ `V1507 ]); + (`LCU20210713, 5004237, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20210713, 5004245, [ `V1909 ]); + (`LCU20210713, 5004244, [ `V1809 ]); + (`LCU20210713, 5004238, [ `V1607 ]); + (`LCU20210713, 5004249, [ `V1507 ]); + (`LCU20210608, 5003637, [ `V2004; `V20H2; `V21H1 ]); + (`LCU20210608, 5003635, [ `V1909 ]); + (`LCU20210608, 5003646, [ `V1809 ]); + (`LCU20210608, 5003638, [ `V1607 ]); + (`LCU20210608, 5003687, [ `V1507 ]); + ] + +let win10_lcu_to_kb : (win10_lcu * win10_release, int option) Hashtbl.t = + let t = Hashtbl.create 63 in + let f (lcu, kb, vs) = + let g v = + if lcu = win10_current_lcu then Hashtbl.add t (`LCU, v) (Some kb); + Hashtbl.add t (lcu, v) (Some kb) + in + List.iter g vs + in + List.iter f win10_lcus; + t + +let win10_kb_to_lcu = + let t = Hashtbl.create 63 in + let f (lcu, kb, vs) = + List.iter (fun v -> Hashtbl.add t (kb, v) (Some lcu)) vs + in + List.iter f win10_lcus; + t + +let win10_lcu_kb_number v lcu = + try Hashtbl.find win10_lcu_to_kb (lcu, v) with Not_found -> None + +let win10_kb_number_to_lcu (v : win10_release) kb = + match Hashtbl.find win10_kb_to_lcu (kb, v) with + | lcu -> Some (v, lcu) + | exception Not_found -> None + +type distro = + [ `Alpine of + [ `V3_3 + | `V3_4 + | `V3_5 + | `V3_6 + | `V3_7 + | `V3_8 + | `V3_9 + | `V3_10 + | `V3_11 + | `V3_12 + | `V3_13 + | `V3_14 + | `V3_15 ] + | `Archlinux of [ `Latest ] + | `CentOS of [ `V6 | `V7 | `V8 ] + | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Testing | `Unstable ] + | `Fedora of + [ `V21 + | `V22 + | `V23 + | `V24 + | `V25 + | `V26 + | `V27 + | `V28 + | `V29 + | `V30 + | `V31 + | `V32 + | `V33 + | `V34 + | `V35 ] + | `OracleLinux of [ `V7 | `V8 ] + | `OpenSUSE of [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 ] + | `Ubuntu of + [ `V12_04 + | `V14_04 + | `V15_04 + | `V15_10 + | `V16_04 + | `V16_10 + | `V17_04 + | `V17_10 + | `V18_04 + | `V18_10 + | `V19_04 + | `V19_10 + | `V20_04 + | `V20_10 + | `V21_04 + | `V21_10 + | `V22_04 ] + | `Cygwin of win10_release + | `Windows of [ `Mingw | `Msvc ] * win10_release ] +[@@deriving sexp] + +type t = + [ `Alpine of + [ `V3_3 + | `V3_4 + | `V3_5 + | `V3_6 + | `V3_7 + | `V3_8 + | `V3_9 + | `V3_10 + | `V3_11 + | `V3_12 + | `V3_13 + | `V3_14 + | `V3_15 + | `Latest ] + | `Archlinux of [ `Latest ] + | `CentOS of [ `V6 | `V7 | `V8 | `Latest ] + | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Stable | `Testing | `Unstable ] + | `Fedora of + [ `V21 + | `V22 + | `V23 + | `V24 + | `V25 + | `V26 + | `V27 + | `V28 + | `V29 + | `V30 + | `V31 + | `V32 + | `V33 + | `V34 + | `V35 + | `Latest ] + | `OracleLinux of [ `V7 | `V8 | `Latest ] + | `OpenSUSE of + [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 | `Latest ] + | `Ubuntu of + [ `V12_04 + | `V14_04 + | `V15_04 + | `V15_10 + | `V16_04 + | `V16_10 + | `V17_04 + | `V17_10 + | `V18_04 + | `V18_10 + | `V19_04 + | `V19_10 + | `V20_04 + | `V20_10 + | `V21_04 + | `V21_10 + | `V22_04 + | `Latest + | `LTS ] + | `Cygwin of win_all + | `Windows of [ `Mingw | `Msvc ] * win_all ] +[@@deriving sexp] + +type os_family = [ `Cygwin | `Linux | `Windows ] [@@deriving sexp] + +let os_family_of_distro (t : t) : os_family = + match t with + | `Alpine _ | `Archlinux _ | `CentOS _ | `Debian _ | `Fedora _ + | `OracleLinux _ | `OpenSUSE _ | `Ubuntu _ -> + `Linux + | `Cygwin _ -> `Cygwin + | `Windows _ -> `Windows + +let os_family_to_string (os : os_family) = + match os with + | `Linux -> "linux" + | `Windows -> "windows" + | `Cygwin -> "cygwin" + +let opam_repository (os : os_family) = + match os with + | `Cygwin | `Linux -> "https://github.com/ocaml/opam-repository.git" + | `Windows -> "https://github.com/fdopen/opam-repository-mingw.git#opam2" + +let personality os_family arch = + match os_family with + | `Linux when Ocaml_version.arch_is_32bit arch -> Some "/usr/bin/linux32" + | _ -> None + +type status = + [ `Deprecated + | `Active of [ `Tier1 | `Tier2 | `Tier3 ] + | `Alias + | `Not_available ] +[@@deriving sexp] + +let distros : t list = + [ + `Alpine `V3_3; + `Alpine `V3_4; + `Alpine `V3_5; + `Alpine `V3_6; + `Alpine `V3_7; + `Alpine `V3_8; + `Alpine `V3_9; + `Alpine `V3_10; + `Alpine `V3_11; + `Alpine `V3_12; + `Alpine `V3_13; + `Alpine `V3_14; + `Alpine `V3_15; + `Alpine `Latest; + `Archlinux `Latest; + `CentOS `V6; + `CentOS `V7; + `CentOS `V8; + `CentOS `Latest; + `Debian `V11; + `Debian `V10; + `Debian `V9; + `Debian `V8; + `Debian `V7; + `Debian `Stable; + `Debian `Testing; + `Debian `Unstable; + `Fedora `V23; + `Fedora `V24; + `Fedora `V25; + `Fedora `V26; + `Fedora `V27; + `Fedora `V28; + `Fedora `V29; + `Fedora `V30; + `Fedora `V31; + `Fedora `V32; + `Fedora `V33; + `Fedora `V34; + `Fedora `V35; + `Fedora `Latest; + `OracleLinux `V7; + `OracleLinux `V8; + `OracleLinux `Latest; + `OpenSUSE `V42_1; + `OpenSUSE `V42_2; + `OpenSUSE `V42_3; + `OpenSUSE `V15_0; + `OpenSUSE `V15_1; + `OpenSUSE `V15_2; + `OpenSUSE `V15_3; + `OpenSUSE `Latest; + `Ubuntu `V12_04; + `Ubuntu `V14_04; + `Ubuntu `V15_04; + `Ubuntu `V15_10; + `Ubuntu `V16_04; + `Ubuntu `V16_10; + `Ubuntu `V17_04; + `Ubuntu `V17_10; + `Ubuntu `V18_04; + `Ubuntu `V18_10; + `Ubuntu `V19_04; + `Ubuntu `V19_10; + `Ubuntu `V20_04; + `Ubuntu `V20_10; + `Ubuntu `V21_04; + `Ubuntu `V21_10; + `Ubuntu `V22_04; + `Ubuntu `Latest; + `Ubuntu `LTS; + ] + +let distros = + let win10_releases = + [ + `V1507; + `Ltsc2015; + `V1511; + `V1607; + `Ltsc2016; + `V1703; + `V1709; + `V1809; + `Ltsc2019; + `V1903; + `V1909; + `V2004; + `V20H2; + `V21H1; + `V21H2; + `Ltsc2022; + ] + in + List.fold_left + (fun distros version -> + `Cygwin version + :: `Windows (`Mingw, version) + :: `Windows (`Msvc, version) + :: distros) + distros win10_releases + +type win10_release_status = [ `Deprecated | `Active ] + +let resolve_ltsc v = + match v with + | `Ltsc2022 -> `V21H2 + | `Ltsc2019 -> `V1809 + | `Ltsc2016 -> `V1607 + | `Ltsc2015 -> `V1507 + | #win10_release as v -> v + +(* https://en.wikipedia.org/wiki/Windows_10_version_history#Channels *) +let win10_release_status v : win10_release_status = + match resolve_ltsc v with + | `V1507 -> `Deprecated + | `Ltsc2015 -> `Active + | `V1511 -> `Deprecated + | `V1607 -> `Deprecated + | `Ltsc2016 -> `Active + | `V1703 | `V1709 | `V1803 | `V1809 -> `Deprecated + | `Ltsc2019 -> `Active + | `V1903 | `V1909 -> `Deprecated + | `V2004 -> `Deprecated + | `V20H2 -> `Deprecated + | `V21H1 | `V21H2 | `Ltsc2022 -> `Active + +let win10_latest_release = `V21H2 + +type win10_docker_base_image = [ `Windows | `ServerCore | `NanoServer ] + +(* https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle *) +let win10_docker_status (base : win10_docker_base_image) v : status = + match (base, v) with + | _, `V21H2 -> `Active `Tier3 + | _, `V20H2 | _, `V2004 | _, `V1909 | _, `V1903 -> `Deprecated + | `ServerCore, `V1809 | `NanoServer, `V1809 | `Windows, `V1809 -> + `Active `Tier3 + | (`ServerCore | `NanoServer), `V1803 | (`ServerCore | `NanoServer), `V1709 -> + `Deprecated + | `ServerCore, `V1607 -> `Active `Tier3 + | `NanoServer, `V1607 -> `Deprecated + | _ -> `Not_available + +let win10_latest_image = `V21H2 + +let resolve_alias (d : t) : distro = + match d with + | `Alpine `Latest -> `Alpine `V3_15 + | `CentOS `Latest -> `CentOS `V7 + | `Debian `Stable -> `Debian `V11 + | `Fedora `Latest -> `Fedora `V35 + | `OracleLinux `Latest -> `OracleLinux `V8 + | `OpenSUSE `Latest -> `OpenSUSE `V15_3 + | `Ubuntu `Latest -> `Ubuntu `V22_04 + | `Ubuntu `LTS -> `Ubuntu `V22_04 + | `Cygwin (#win10_ltsc as v) -> `Cygwin (resolve_ltsc v) + | `Windows (cc, (#win10_ltsc as v)) -> `Windows (cc, resolve_ltsc v) + | ( `Alpine + ( `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 + | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15 ) + | `Archlinux `Latest + | `CentOS (`V6 | `V7 | `V8) + | `Debian (`V7 | `V8 | `V9 | `V10 | `V11 | `Testing | `Unstable) + | `Fedora + ( `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 + | `V31 | `V32 | `V33 | `V34 | `V35 ) + | `OracleLinux (`V7 | `V8) + | `OpenSUSE (`V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3) + | `Ubuntu + ( `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 + | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 + | `V21_04 | `V21_10 | `V22_04 ) + | `Cygwin + ( `V1507 | `V1511 | `V1607 | `V1703 | `V1709 | `V1803 | `V1809 | `V1903 + | `V1909 | `V2004 | `V20H2 | `V21H1 | `V21H2 ) + | `Windows + ( _, + ( `V1507 | `V1511 | `V1607 | `V1703 | `V1709 | `V1803 | `V1809 + | `V1903 | `V1909 | `V2004 | `V20H2 | `V21H1 | `V21H2 ) ) ) as d -> + d + +let distro_status (d : t) : status = + let resolved = resolve_alias d in + if (resolved : distro :> t) <> d then `Alias + else + match resolve_alias d with + | `Alpine + ( `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 + | `V3_11 | `V3_12 | `V3_13 ) -> + `Deprecated + | `Alpine `V3_14 -> `Active `Tier2 + | `Alpine `V3_15 -> `Active `Tier1 + | `Archlinux `Latest -> `Active `Tier3 + | `CentOS `V7 -> `Active `Tier3 + | `CentOS (`V6 | `V8) -> `Deprecated + | `Debian (`V7 | `V8 | `V9) -> `Deprecated + | `Debian `V10 -> `Active `Tier2 + | `Debian `V11 -> `Active `Tier1 + | `Debian `Testing -> `Active `Tier3 + | `Debian `Unstable -> `Active `Tier3 + | `Fedora + ( `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 + | `V31 | `V32 | `V33 ) -> + `Deprecated + | `Fedora (`V34 | `V35) -> `Active `Tier2 + | `OracleLinux (`V7 | `V8) -> `Active `Tier3 + | `OpenSUSE (`V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2) -> + `Deprecated + | `OpenSUSE `V15_3 -> `Active `Tier2 + | `Ubuntu `V18_04 -> `Active `Tier3 + | `Ubuntu (`V20_04 | `V22_04) -> `Active `Tier2 + | `Ubuntu + ( `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 + | `V17_10 | `V18_10 | `V19_04 | `V19_10 | `V20_10 | `V21_04 | `V21_10 ) + -> + `Deprecated + | `Cygwin v -> win10_docker_status `ServerCore v + | `Windows (_, v) -> win10_docker_status `Windows v + +let latest_distros = + [ + `Alpine `Latest; + `Archlinux `Latest; + `CentOS `Latest; + `Debian `Stable; + `OracleLinux `Latest; + `OpenSUSE `Latest; + `Fedora `Latest; + `Ubuntu `Latest; + `Ubuntu `LTS; + (* Prefer win10_latest_image to win10_latest_release as + latest_distro is used by docker-base-images to fetch tag + aliases. *) + `Cygwin win10_latest_image; + `Windows (`Mingw, win10_latest_image); + `Windows (`Msvc, win10_latest_image); + ] + +let master_distro = `Debian `Stable + +module OV = Ocaml_version + +let distro_arches ov (d : t) = + match (resolve_alias d, ov) with + | `Windows (`Msvc, _), ov when OV.major ov >= 5 -> [] + | (`CentOS (`V6 | `V7) | `OracleLinux `V7), ov when OV.major ov >= 5 -> [] + | `Debian `V11, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> + [ `I386; `X86_64; `Aarch64; `Aarch32; `Ppc64le; `S390x ] + | `Debian `V11, ov when OV.(compare Releases.v4_02_0 ov) = -1 -> + [ `I386; `X86_64; `Aarch64; `Aarch32 ] + | `Debian `V10, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> + [ `I386; `X86_64; `Aarch64; `Aarch32; `Ppc64le; `S390x ] + | `Debian `V10, ov when OV.(compare Releases.v4_02_0 ov) = -1 -> + [ `I386; `X86_64; `Aarch64; `Aarch32 ] + | `Debian `V9, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> + [ `I386; `X86_64; `Aarch64; `Aarch32 ] + | ( `Alpine + ( `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 + | `V3_14 | `V3_15 ), + ov ) + when OV.(compare Releases.v4_05_0 ov) = -1 -> + [ `X86_64; `Aarch64 ] + | `Ubuntu `V18_04, ov when OV.(compare Releases.v4_05_0 ov) = -1 -> + [ `X86_64; `Aarch64; `Ppc64le; `S390x ] + | `Ubuntu (`V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04), ov + when OV.(compare Releases.v4_05_0 ov) = -1 -> + let base = [ `X86_64; `Aarch64; `Ppc64le; `S390x ] in + if OV.(compare Releases.v4_11_0 ov) <= 0 then `Riscv64 :: base else base + | `Fedora (`V33 | `V34 | `V35), ov when OV.(compare Releases.v4_08_0 ov) = -1 + -> + [ `X86_64; `Aarch64 ] + (* 2021-04-19: should be 4.03 but there's a linking failure until 4.06. *) + | `Windows (`Msvc, _), ov when OV.(compare Releases.v4_06_0 ov) = 1 -> [] + | _ -> [ `X86_64 ] + +let distro_supported_on a ov (d : t) = List.mem a (distro_arches ov d) + +let distro_active_for arch (d : t) = + match (arch, d) with + | `X86_64, `Windows _ -> true + | _ -> distro_supported_on arch OV.Releases.latest d + +let active_distros arch = + List.filter + (fun d -> match distro_status d with `Active _ -> true | _ -> false) + distros + |> List.filter (distro_active_for arch) + +let active_tier1_distros arch = + List.filter + (fun d -> match distro_status d with `Active `Tier1 -> true | _ -> false) + distros + |> List.filter (distro_active_for arch) + +let active_tier2_distros arch = + List.filter + (fun d -> match distro_status d with `Active `Tier2 -> true | _ -> false) + distros + |> List.filter (distro_active_for arch) + +let active_tier3_distros arch = + List.filter + (fun d -> match distro_status d with `Active `Tier3 -> true | _ -> false) + distros + |> List.filter (distro_active_for arch) + +(* The distro-supplied version of OCaml *) +let builtin_ocaml_of_distro (d : t) : string option = + match resolve_alias d with + | `Debian `V7 -> Some "3.12.1" + | `Debian `V8 -> Some "4.01.0" + | `Debian `V9 -> Some "4.02.3" + | `Debian `V10 -> Some "4.05.0" + | `Debian `V11 -> Some "4.11.1" + | `Ubuntu `V12_04 -> Some "3.12.1" + | `Ubuntu `V14_04 -> Some "4.01.0" + | `Ubuntu `V15_04 -> Some "4.01.0" + | `Ubuntu `V15_10 -> Some "4.01.0" + | `Ubuntu `V16_04 -> Some "4.02.3" + | `Ubuntu `V16_10 -> Some "4.02.3" + | `Ubuntu `V17_04 -> Some "4.02.3" + | `Ubuntu `V17_10 -> Some "4.04.0" + | `Ubuntu `V18_04 -> Some "4.05.0" + | `Ubuntu `V18_10 -> Some "4.05.0" + | `Ubuntu `V19_04 -> Some "4.05.0" + | `Ubuntu `V19_10 -> Some "4.05.0" + | `Ubuntu `V20_04 -> Some "4.08.1" + | `Ubuntu `V20_10 -> Some "4.08.1" + | `Ubuntu `V21_04 -> Some "4.11.1" + | `Ubuntu `V21_10 -> Some "4.11.1" + | `Ubuntu `V22_04 -> failwith "4.11.1; not yet confirmed" + | `Alpine `V3_3 -> Some "4.02.3" + | `Alpine `V3_4 -> Some "4.02.3" + | `Alpine `V3_5 -> Some "4.04.0" + | `Alpine `V3_6 -> Some "4.04.1" + | `Alpine `V3_7 -> Some "4.04.2" + | `Alpine `V3_8 -> Some "4.06.1" + | `Alpine `V3_9 -> Some "4.06.1" + | `Alpine `V3_10 -> Some "4.07.0" + | `Alpine `V3_11 -> Some "4.08.1" + | `Alpine `V3_12 -> Some "4.08.1" + | `Alpine `V3_13 -> Some "4.08.1" + | `Alpine `V3_14 -> Some "4.12.0" + | `Alpine `V3_15 -> Some "4.13.1" + | `Archlinux `Latest -> Some "4.11.1" + | `Fedora `V21 -> Some "4.01.0" + | `Fedora `V22 -> Some "4.02.0" + | `Fedora `V23 -> Some "4.02.2" + | `Fedora `V24 -> Some "4.02.3" + | `Fedora `V25 -> Some "4.02.3" + | `Fedora `V26 -> Some "4.04.0" + | `Fedora `V27 -> Some "4.05.0" + | `Fedora `V28 -> Some "4.06.0" + | `Fedora `V29 -> Some "4.07.0" + | `Fedora `V30 -> Some "4.07.0" + | `Fedora `V31 -> Some "4.08.1" + | `Fedora `V32 -> Some "4.10.0" + | `Fedora `V33 -> Some "4.11.1" + | `Fedora `V34 -> Some "4.11.1" + | `Fedora `V35 -> Some "4.12.0" + | `CentOS `V6 -> Some "3.11.2" + | `CentOS `V7 -> Some "4.01.0" + | `CentOS `V8 -> Some "4.07.0" + | `OpenSUSE `V42_1 -> Some "4.02.3" + | `OpenSUSE `V42_2 -> Some "4.03.0" + | `OpenSUSE `V42_3 -> Some "4.03.0" + | `OpenSUSE `V15_0 -> Some "4.05.0" + | `OpenSUSE `V15_1 -> Some "4.05.0" + | `OpenSUSE `V15_2 -> Some "4.05.0" + | `OpenSUSE `V15_3 -> Some "4.05.0" + | `OracleLinux `V7 -> Some "4.01.0" + | `OracleLinux `V8 -> Some "4.07.0" + | `Cygwin _ -> None + | `Windows _ -> None + | `Debian (`Testing | `Unstable) -> assert false + +let win10_release_to_string = function + | `V1507 -> "1507" + | `Ltsc2015 -> "ltsc2015" + | `V1511 -> "1511" + | `V1607 -> "1607" + | `Ltsc2016 -> "ltsc2016" + | `V1703 -> "1703" + | `V1709 -> "1709" + | `V1803 -> "1803" + | `V1809 -> "1809" + | `Ltsc2019 -> "ltsc2019" + | `V1903 -> "1903" + | `V1909 -> "1909" + | `V2004 -> "2004" + | `V20H2 -> "20H2" + | `V21H1 -> "21H1" + | `Ltsc2022 -> "ltsc2022" + | `V21H2 -> "21H2" + +let win10_release_of_string v : win_all option = + let v = + match String.cut ~sep:"-KB" v with + | Some (v, kb) -> if String.for_all Char.Ascii.is_digit kb then v else "" + | None -> v + in + match v with + | "1507" -> Some `V1507 + | "ltsc2015" -> Some `Ltsc2015 + | "1511" -> Some `V1511 + | "1607" -> Some `V1607 + | "ltsc2016" -> Some `Ltsc2016 + | "1703" -> Some `V1703 + | "1709" -> Some `V1709 + | "1803" -> Some `V1803 + | "1809" -> Some `V1809 + | "ltsc2019" -> Some `Ltsc2019 + | "1903" -> Some `V1903 + | "1909" -> Some `V1909 + | "2004" -> Some `V2004 + | "20H2" -> Some `V20H2 + | "21H1" -> Some `V21H1 + | "ltsc2022" -> Some `Ltsc2022 + | _ -> None + +let rec win10_revision_to_string = function + | v, None -> win10_release_to_string v + | v, Some `LCU -> win10_revision_to_string (v, Some win10_current_lcu) + | v, Some lcu -> ( + match win10_lcu_kb_number (resolve_ltsc v) lcu with + | Some kb -> Printf.sprintf "%s-KB%d" (win10_release_to_string v) kb + | None -> + Fmt.invalid_arg "No KB for this Win10 %s revision" + (win10_release_to_string v)) + +let win10_revision_of_string v = + let v, lcu = + match String.cut ~sep:"-KB" v with + | Some (v, lcu) when String.for_all Char.Ascii.is_digit lcu -> + (v, Some (int_of_string lcu)) + | _ -> (v, None) + in + match win10_release_of_string v with + | None -> None + | Some v -> ( + let v = resolve_ltsc v in + match lcu with + | None -> Some (v, None) + | Some lcu -> win10_kb_number_to_lcu v lcu) + +(* The Docker tag for this distro *) +let tag_of_distro (d : t) = + match d with + | `Ubuntu `V12_04 -> "ubuntu-12.04" + | `Ubuntu `V14_04 -> "ubuntu-14.04" + | `Ubuntu `V15_04 -> "ubuntu-15.04" + | `Ubuntu `V15_10 -> "ubuntu-15.10" + | `Ubuntu `V16_04 -> "ubuntu-16.04" + | `Ubuntu `V16_10 -> "ubuntu-16.10" + | `Ubuntu `V17_04 -> "ubuntu-17.04" + | `Ubuntu `V17_10 -> "ubuntu-17.10" + | `Ubuntu `V18_04 -> "ubuntu-18.04" + | `Ubuntu `V18_10 -> "ubuntu-18.10" + | `Ubuntu `V19_04 -> "ubuntu-19.04" + | `Ubuntu `V19_10 -> "ubuntu-19.10" + | `Ubuntu `V20_04 -> "ubuntu-20.04" + | `Ubuntu `V20_10 -> "ubuntu-20.10" + | `Ubuntu `V21_04 -> "ubuntu-21.04" + | `Ubuntu `V21_10 -> "ubuntu-21.10" + | `Ubuntu `V22_04 -> "ubuntu-22.04" + | `Ubuntu `Latest -> "ubuntu" + | `Ubuntu `LTS -> "ubuntu-lts" + | `Debian `Stable -> "debian-stable" + | `Debian `Unstable -> "debian-unstable" + | `Debian `Testing -> "debian-testing" + | `Debian `V11 -> "debian-11" + | `Debian `V10 -> "debian-10" + | `Debian `V9 -> "debian-9" + | `Debian `V8 -> "debian-8" + | `Debian `V7 -> "debian-7" + | `CentOS `V6 -> "centos-6" + | `CentOS `V7 -> "centos-7" + | `CentOS `V8 -> "centos-8" + | `CentOS `Latest -> "centos" + | `Fedora `Latest -> "fedora" + | `Fedora `V21 -> "fedora-21" + | `Fedora `V22 -> "fedora-22" + | `Fedora `V23 -> "fedora-23" + | `Fedora `V24 -> "fedora-24" + | `Fedora `V25 -> "fedora-25" + | `Fedora `V26 -> "fedora-26" + | `Fedora `V27 -> "fedora-27" + | `Fedora `V28 -> "fedora-28" + | `Fedora `V29 -> "fedora-29" + | `Fedora `V30 -> "fedora-30" + | `Fedora `V31 -> "fedora-31" + | `Fedora `V32 -> "fedora-32" + | `Fedora `V33 -> "fedora-33" + | `Fedora `V34 -> "fedora-34" + | `Fedora `V35 -> "fedora-35" + | `OracleLinux `V7 -> "oraclelinux-7" + | `OracleLinux `V8 -> "oraclelinux-8" + | `OracleLinux `Latest -> "oraclelinux" + | `Alpine `V3_3 -> "alpine-3.3" + | `Alpine `V3_4 -> "alpine-3.4" + | `Alpine `V3_5 -> "alpine-3.5" + | `Alpine `V3_6 -> "alpine-3.6" + | `Alpine `V3_7 -> "alpine-3.7" + | `Alpine `V3_8 -> "alpine-3.8" + | `Alpine `V3_9 -> "alpine-3.9" + | `Alpine `V3_10 -> "alpine-3.10" + | `Alpine `V3_11 -> "alpine-3.11" + | `Alpine `V3_12 -> "alpine-3.12" + | `Alpine `V3_13 -> "alpine-3.13" + | `Alpine `V3_14 -> "alpine-3.14" + | `Alpine `V3_15 -> "alpine-3.15" + | `Alpine `Latest -> "alpine" + | `Archlinux `Latest -> "archlinux" + | `OpenSUSE `V42_1 -> "opensuse-42.1" + | `OpenSUSE `V42_2 -> "opensuse-42.2" + | `OpenSUSE `V42_3 -> "opensuse-42.3" + | `OpenSUSE `V15_0 -> "opensuse-15.0" + | `OpenSUSE `V15_1 -> "opensuse-15.1" + | `OpenSUSE `V15_2 -> "opensuse-15.2" + | `OpenSUSE `V15_3 -> "opensuse-15.3" + | `OpenSUSE `Latest -> "opensuse" + | `Cygwin v -> "cygwin-" ^ win10_release_to_string v + | `Windows (`Mingw, v) -> "windows-mingw-" ^ win10_release_to_string v + | `Windows (`Msvc, v) -> "windows-msvc-" ^ win10_release_to_string v + +let distro_of_tag x : t option = + let win10_of_tag affix s f = + let stop = String.length affix in + match + win10_release_of_string String.(sub ~start:0 ~stop s |> Sub.to_string) + with + | Some v -> Some (f v) + | None -> None + in + match x with + | "ubuntu-12.04" -> Some (`Ubuntu `V12_04) + | "ubuntu-14.04" -> Some (`Ubuntu `V14_04) + | "ubuntu-15.04" -> Some (`Ubuntu `V15_04) + | "ubuntu-15.10" -> Some (`Ubuntu `V15_10) + | "ubuntu-16.04" -> Some (`Ubuntu `V16_04) + | "ubuntu-16.10" -> Some (`Ubuntu `V16_10) + | "ubuntu-17.04" -> Some (`Ubuntu `V17_04) + | "ubuntu-17.10" -> Some (`Ubuntu `V17_10) + | "ubuntu-18.04" -> Some (`Ubuntu `V18_04) + | "ubuntu-18.10" -> Some (`Ubuntu `V18_10) + | "ubuntu-19.04" -> Some (`Ubuntu `V19_04) + | "ubuntu-19.10" -> Some (`Ubuntu `V19_10) + | "ubuntu-20.04" -> Some (`Ubuntu `V20_04) + | "ubuntu-20.10" -> Some (`Ubuntu `V20_10) + | "ubuntu-21.04" -> Some (`Ubuntu `V21_04) + | "ubuntu-21.10" -> Some (`Ubuntu `V21_10) + | "ubuntu-22.04" -> Some (`Ubuntu `V22_04) + | "ubuntu" -> Some (`Ubuntu `Latest) + | "ubuntu-lts" -> Some (`Ubuntu `LTS) + | "debian-stable" -> Some (`Debian `Stable) + | "debian-unstable" -> Some (`Debian `Unstable) + | "debian-testing" -> Some (`Debian `Testing) + | "debian-11" -> Some (`Debian `V11) + | "debian-10" -> Some (`Debian `V10) + | "debian-9" -> Some (`Debian `V9) + | "debian-8" -> Some (`Debian `V8) + | "debian-7" -> Some (`Debian `V7) + | "centos-6" -> Some (`CentOS `V6) + | "centos-7" -> Some (`CentOS `V7) + | "centos-8" -> Some (`CentOS `V8) + | "fedora-21" -> Some (`Fedora `V21) + | "fedora-22" -> Some (`Fedora `V22) + | "fedora-23" -> Some (`Fedora `V23) + | "fedora-24" -> Some (`Fedora `V24) + | "fedora-25" -> Some (`Fedora `V25) + | "fedora-26" -> Some (`Fedora `V26) + | "fedora-27" -> Some (`Fedora `V27) + | "fedora-28" -> Some (`Fedora `V28) + | "fedora-29" -> Some (`Fedora `V29) + | "fedora-30" -> Some (`Fedora `V30) + | "fedora-31" -> Some (`Fedora `V31) + | "fedora-32" -> Some (`Fedora `V32) + | "fedora-33" -> Some (`Fedora `V33) + | "fedora-34" -> Some (`Fedora `V34) + | "fedora-35" -> Some (`Fedora `V35) + | "fedora" -> Some (`Fedora `Latest) + | "oraclelinux-7" -> Some (`OracleLinux `V7) + | "oraclelinux-8" -> Some (`OracleLinux `V8) + | "oraclelinux" -> Some (`OracleLinux `Latest) + | "alpine-3.3" -> Some (`Alpine `V3_3) + | "alpine-3.4" -> Some (`Alpine `V3_4) + | "alpine-3.5" -> Some (`Alpine `V3_5) + | "alpine-3.6" -> Some (`Alpine `V3_6) + | "alpine-3.7" -> Some (`Alpine `V3_7) + | "alpine-3.8" -> Some (`Alpine `V3_8) + | "alpine-3.9" -> Some (`Alpine `V3_9) + | "alpine-3.10" -> Some (`Alpine `V3_10) + | "alpine-3.11" -> Some (`Alpine `V3_11) + | "alpine-3.12" -> Some (`Alpine `V3_12) + | "alpine-3.13" -> Some (`Alpine `V3_13) + | "alpine-3.14" -> Some (`Alpine `V3_14) + | "alpine-3.15" -> Some (`Alpine `V3_15) + | "alpine" -> Some (`Alpine `Latest) + | "archlinux" -> Some (`Archlinux `Latest) + | "opensuse-42.1" -> Some (`OpenSUSE `V42_1) + | "opensuse-42.2" -> Some (`OpenSUSE `V42_2) + | "opensuse-42.3" -> Some (`OpenSUSE `V42_3) + | "opensuse-15.0" -> Some (`OpenSUSE `V15_0) + | "opensuse-15.1" -> Some (`OpenSUSE `V15_1) + | "opensuse-15.2" -> Some (`OpenSUSE `V15_2) + | "opensuse-15.3" -> Some (`OpenSUSE `V15_3) + | "opensuse" -> Some (`OpenSUSE `Latest) + | s when String.is_prefix ~affix:"cygwin-" s -> + win10_of_tag "cygwin-" s (fun v -> `Cygwin v) + | s when String.is_prefix ~affix:"windows-mingw-" s -> + win10_of_tag "windows-mingw-" s (fun v -> `Windows (`Mingw, v)) + | s when String.is_prefix ~affix:"windows-msvc-" s -> + win10_of_tag "windows-msvc-" s (fun v -> `Windows (`Msvc, v)) + | _ -> None + +let human_readable_string_of_distro (d : t) = + if d = `Debian `Stable then "Debian Stable" + else + match resolve_alias d with + | `Ubuntu `V12_04 -> "Ubuntu 12.04" + | `Ubuntu `V14_04 -> "Ubuntu 14.04" + | `Ubuntu `V15_04 -> "Ubuntu 15.04" + | `Ubuntu `V15_10 -> "Ubuntu 15.10" + | `Ubuntu `V16_04 -> "Ubuntu 16.04" + | `Ubuntu `V16_10 -> "Ubuntu 16.10" + | `Ubuntu `V17_04 -> "Ubuntu 17.04" + | `Ubuntu `V17_10 -> "Ubuntu 17.10" + | `Ubuntu `V18_04 -> "Ubuntu 18.04" + | `Ubuntu `V18_10 -> "Ubuntu 18.10" + | `Ubuntu `V19_04 -> "Ubuntu 19.04" + | `Ubuntu `V19_10 -> "Ubuntu 19.10" + | `Ubuntu `V20_04 -> "Ubuntu 20.04" + | `Ubuntu `V20_10 -> "Ubuntu 20.10" + | `Ubuntu `V21_04 -> "Ubuntu 21.04" + | `Ubuntu `V21_10 -> "Ubuntu 21.10" + | `Ubuntu `V22_04 -> "Ubuntu 22.04" + | `Debian `Unstable -> "Debian Unstable" + | `Debian `Testing -> "Debian Testing" + | `Debian `V11 -> "Debian 11 (Bullseye)" + | `Debian `V10 -> "Debian 10 (Buster)" + | `Debian `V9 -> "Debian 9 (Stretch)" + | `Debian `V8 -> "Debian 8 (Jessie)" + | `Debian `V7 -> "Debian 7 (Wheezy)" + | `CentOS `V6 -> "CentOS 6" + | `CentOS `V7 -> "CentOS 7" + | `CentOS `V8 -> "CentOS 8" + | `Fedora `V21 -> "Fedora 21" + | `Fedora `V22 -> "Fedora 22" + | `Fedora `V23 -> "Fedora 23" + | `Fedora `V24 -> "Fedora 24" + | `Fedora `V25 -> "Fedora 25" + | `Fedora `V26 -> "Fedora 26" + | `Fedora `V27 -> "Fedora 27" + | `Fedora `V28 -> "Fedora 28" + | `Fedora `V29 -> "Fedora 29" + | `Fedora `V30 -> "Fedora 30" + | `Fedora `V31 -> "Fedora 31" + | `Fedora `V32 -> "Fedora 32" + | `Fedora `V33 -> "Fedora 33" + | `Fedora `V34 -> "Fedora 34" + | `Fedora `V35 -> "Fedora 35" + | `OracleLinux `V7 -> "OracleLinux 7" + | `OracleLinux `V8 -> "OracleLinux 8" + | `Alpine `V3_3 -> "Alpine 3.3" + | `Alpine `V3_4 -> "Alpine 3.4" + | `Alpine `V3_5 -> "Alpine 3.5" + | `Alpine `V3_6 -> "Alpine 3.6" + | `Alpine `V3_7 -> "Alpine 3.7" + | `Alpine `V3_8 -> "Alpine 3.8" + | `Alpine `V3_9 -> "Alpine 3.9" + | `Alpine `V3_10 -> "Alpine 3.10" + | `Alpine `V3_11 -> "Alpine 3.11" + | `Alpine `V3_12 -> "Alpine 3.12" + | `Alpine `V3_13 -> "Alpine 3.13" + | `Alpine `V3_14 -> "Alpine 3.14" + | `Alpine `V3_15 -> "Alpine 3.15" + | `Archlinux `Latest -> "Archlinux" + | `OpenSUSE `V42_1 -> "OpenSUSE 42.1" + | `OpenSUSE `V42_2 -> "OpenSUSE 42.2" + | `OpenSUSE `V42_3 -> "OpenSUSE 42.3" + | `OpenSUSE `V15_0 -> "OpenSUSE 15.0 (Leap)" + | `OpenSUSE `V15_1 -> "OpenSUSE 15.1 (Leap)" + | `OpenSUSE `V15_2 -> "OpenSUSE 15.2 (Leap)" + | `OpenSUSE `V15_3 -> "OpenSUSE 15.3 (Leap)" + | `Cygwin v -> "Cygwin " ^ win10_release_to_string v + | `Windows (`Mingw, v) -> "Windows mingw " ^ win10_release_to_string v + | `Windows (`Msvc, v) -> "Windows mingw " ^ win10_release_to_string v + +let human_readable_short_string_of_distro (t : t) = + match t with + | `Ubuntu _ -> "Ubuntu" + | `Debian _ -> "Debian" + | `CentOS _ -> "CentOS" + | `Fedora _ -> "Fedora" + | `OracleLinux _ -> "OracleLinux" + | `Alpine _ -> "Alpine" + | `Archlinux _ -> "Archlinux" + | `OpenSUSE _ -> "OpenSUSE" + | `Cygwin _ -> "Cygwin" + | `Windows (`Mingw, _) -> "Windows mingw" + | `Windows (`Msvc, _) -> "Windows mvsc" + +let is_same_distro (d1 : t) (d2 : t) = + match (d1, d2) with + | `Ubuntu _, `Ubuntu _ + | `Debian _, `Debian _ + | `CentOS _, `CentOS _ + | `Fedora _, `Fedora _ + | `OracleLinux _, `OracleLinux _ + | `Alpine _, `Alpine _ + | `Archlinux _, `Archlinux _ + | `OpenSUSE _, `OpenSUSE _ + | `Cygwin _, `Cygwin _ -> + true + | `Windows (p1, _), `Windows (p2, _) when p1 = p2 -> true + | _ -> false + +(* The alias tag for the latest stable version of this distro *) +let latest_tag_of_distro (t : t) = + let latest = List.find (is_same_distro t) latest_distros in + tag_of_distro latest + +type package_manager = + [ `Apt | `Yum | `Apk | `Zypper | `Pacman | `Cygwin | `Windows ] +[@@deriving sexp] + +let package_manager (t : t) = + match t with + | `Ubuntu _ -> `Apt + | `Debian _ -> `Apt + | `CentOS _ -> `Yum + | `Fedora _ -> `Yum + | `OracleLinux _ -> `Yum + | `Alpine _ -> `Apk + | `Archlinux _ -> `Pacman + | `OpenSUSE _ -> `Zypper + | `Cygwin _ -> `Cygwin + | `Windows _ -> `Windows + +let rec bubblewrap_version (t : t) = + match resolve_alias t with + | `Ubuntu `V12_04 -> None + | `Ubuntu `V14_04 -> None + | `Ubuntu `V15_04 -> None + | `Ubuntu `V15_10 -> None + | `Ubuntu `V16_04 -> None + | `Ubuntu `V16_10 -> None (* Not actually checked *) + | `Ubuntu `V17_04 -> None (* Not actually checked *) + | `Ubuntu `V17_10 -> None (* Not actually checked *) + | `Ubuntu `V18_04 -> Some (0, 2, 1) + | `Ubuntu `V18_10 -> Some (0, 2, 1) (* Not actually checked *) + | `Ubuntu `V19_04 -> Some (0, 2, 1) (* Not actually checked *) + | `Ubuntu `V19_10 -> Some (0, 2, 1) (* Not actually checked *) + | `Ubuntu `V20_04 -> Some (0, 4, 0) + | `Ubuntu `V20_10 -> Some (0, 4, 0) (* Not actually checked *) + | `Ubuntu `V21_04 -> Some (0, 4, 1) + | `Ubuntu `V21_10 -> Some (0, 4, 1) + | `Ubuntu `V22_04 -> Some (0, 5, 0) + | `Debian `V7 -> None (* Not actually checked *) + | `Debian `V8 -> None (* Not actually checked *) + | `Debian `V9 -> Some (0, 3, 1) + | `Debian `V10 -> Some (0, 3, 1) + | `Debian `V11 -> Some (0, 4, 1) + | `Debian `Testing -> Some (0, 5, 0) + | `Debian `Unstable -> Some (0, 5, 0) + | `CentOS `V6 -> None + | `CentOS `V7 -> None + | `CentOS `V8 -> Some (0, 4, 0) + | `Fedora `V21 -> None (* Not actually checked *) + | `Fedora `V22 -> None (* Not actually checked *) + | `Fedora `V23 -> None (* Not actually checked *) + | `Fedora `V24 -> None (* Not actually checked *) + | `Fedora `V25 -> None (* Not actually checked *) + | `Fedora `V26 -> Some (0, 2, 0) + | `Fedora `V27 -> Some (0, 2, 1) + | `Fedora `V28 -> Some (0, 3, 0) + | `Fedora `V29 -> Some (0, 3, 1) + | `Fedora `V30 -> Some (0, 3, 3) + | `Fedora `V31 -> Some (0, 4, 1) + | `Fedora `V32 -> Some (0, 4, 1) + | `Fedora `V33 -> Some (0, 4, 1) + | `Fedora `V34 -> Some (0, 4, 1) + | `Fedora `V35 -> Some (0, 5, 0) + | `OracleLinux ((`V7 | `V8) as v) -> bubblewrap_version (`CentOS v) + | `Alpine `V3_3 -> None (* Not actually checked *) + | `Alpine `V3_4 -> None (* Not actually checked *) + | `Alpine `V3_5 -> None (* Not actually checked *) + | `Alpine `V3_6 -> None (* Not actually checked *) + | `Alpine `V3_7 -> None (* Not actually checked *) + | `Alpine `V3_8 -> Some (0, 2, 0) + | `Alpine `V3_9 -> Some (0, 3, 1) + | `Alpine `V3_10 -> Some (0, 3, 3) + | `Alpine `V3_11 -> Some (0, 4, 1) + | `Alpine `V3_12 -> Some (0, 4, 1) + | `Alpine `V3_13 -> Some (0, 4, 1) + | `Alpine `V3_14 -> Some (0, 4, 1) + | `Alpine `V3_15 -> Some (0, 5, 0) + | `Archlinux `Latest -> Some (0, 5, 0) + | `OpenSUSE `V42_1 -> None (* Not actually checked *) + | `OpenSUSE `V42_2 -> None (* Not actually checked *) + | `OpenSUSE `V42_3 -> None (* Not actually checked *) + | `OpenSUSE `V15_0 -> Some (0, 2, 0) + | `OpenSUSE `V15_1 -> Some (0, 3, 3) + | `OpenSUSE `V15_2 -> Some (0, 4, 1) + | `OpenSUSE `V15_3 -> Some (0, 4, 1) + | `Cygwin _ -> None + | `Windows _ -> None + +let win10_base_tag ?win10_revision (base : win10_docker_base_image) v = + let base, v = + match (base, resolve_ltsc v) with + | `NanoServer, _ -> ("mcr.microsoft.com/windows/nanoserver", v) + | `ServerCore, _ -> ("mcr.microsoft.com/windows/servercore", v) + | `Windows, `V21H2 -> ("mcr.microsoft.com/windows/server", `Ltsc2022) + | `Windows, _ -> ("mcr.microsoft.com/windows", v) + in + (base, win10_revision_to_string (v, win10_revision)) + +let base_distro_tag ?win10_revision ?(arch = `X86_64) d = + match resolve_alias d with + | `Alpine v -> ( + let tag = + match v with + | `V3_3 -> "3.3" + | `V3_4 -> "3.4" + | `V3_5 -> "3.5" + | `V3_6 -> "3.6" + | `V3_7 -> "3.7" + | `V3_8 -> "3.8" + | `V3_9 -> "3.9" + | `V3_10 -> "3.10" + | `V3_11 -> "3.11" + | `V3_12 -> "3.12" + | `V3_13 -> "3.13" + | `V3_14 -> "3.14" + | `V3_15 -> "3.15" + in + match arch with `I386 -> ("i386/alpine", tag) | _ -> ("alpine", tag)) + | `Archlinux `Latest -> ("archlinux", "latest") + | `Debian v -> ( + let tag = + match v with + | `V7 -> "7" + | `V8 -> "8" + | `V9 -> "9" + | `V10 -> "10" + | `V11 -> "11" + | `Testing -> "testing" + | `Unstable -> "unstable" + in + match arch with + | `I386 -> ("i386/debian", tag) + | `Aarch32 -> ("arm32v7/debian", tag) + | _ -> ("debian", tag)) + | `Ubuntu v -> + let tag = + match v with + | `V12_04 -> "precise" + | `V14_04 -> "trusty" + | `V15_04 -> "vivid" + | `V15_10 -> "wily" + | `V16_04 -> "xenial" + | `V16_10 -> "yakkety" + | `V17_04 -> "zesty" + | `V17_10 -> "artful" + | `V18_04 -> "bionic" + | `V18_10 -> "cosmic" + | `V19_04 -> "disco" + | `V19_10 -> "eoan" + | `V20_04 -> "focal" + | `V20_10 -> "groovy" + | `V21_04 -> "hirsute" + | `V21_10 -> "impish" + | `V22_04 -> "jammy" + in + ("ubuntu", tag) + | `CentOS v -> + let tag = match v with `V6 -> "6" | `V7 -> "7" | `V8 -> "8" in + ("centos", tag) + | `Fedora v -> + let tag = + match v with + | `V21 -> "21" + | `V22 -> "22" + | `V23 -> "23" + | `V24 -> "24" + | `V25 -> "25" + | `V26 -> "26" + | `V27 -> "27" + | `V28 -> "28" + | `V29 -> "29" + | `V30 -> "30" + | `V31 -> "31" + | `V32 -> "32" + | `V33 -> "33" + | `V34 -> "34" + | `V35 -> "35" + in + ("fedora", tag) + | `OracleLinux v -> + let tag = match v with `V7 -> "7" | `V8 -> "8" in + ("oraclelinux", tag) + | `OpenSUSE v -> + let tag = + match v with + | `V42_1 -> "42.1" + | `V42_2 -> "42.2" + | `V42_3 -> "42.3" + | `V15_0 -> "15.0" + | `V15_1 -> "15.1" + | `V15_2 -> "15.2" + | `V15_3 -> "15.3" + in + ("opensuse/leap", tag) + | `Cygwin v -> + win10_base_tag ?win10_revision `ServerCore + (v : win10_release :> [> win10_release ]) + | `Windows (_, v) -> + win10_base_tag ?win10_revision `Windows + (v : win10_release :> [> win10_release ]) + +let compare a b = + String.compare + (human_readable_string_of_distro a) + (human_readable_string_of_distro b) diff --git a/src-opam/dockerfile_distro.mli b/src-opam/distro.mli similarity index 78% rename from src-opam/dockerfile_distro.mli rename to src-opam/distro.mli index 3bf10398..f55fb129 100644 --- a/src-opam/dockerfile_distro.mli +++ b/src-opam/distro.mli @@ -22,24 +22,33 @@ (** {2 Known distributions and OCaml variants} *) -type win10_release = [ - | `V1507 | `V1511 | `V1607 - | `V1703 | `V1709 | `V1803 | `V1809 | `V1903 | `V1909 - | `V2004 | `V20H2 | `V21H1 | `V21H2 -] [@@deriving sexp] +type win10_release = + [ `V1507 + | `V1511 + | `V1607 + | `V1703 + | `V1709 + | `V1803 + | `V1809 + | `V1903 + | `V1909 + | `V2004 + | `V20H2 + | `V21H1 + | `V21H2 ] +[@@deriving sexp] (** All Windows 10 release versions. *) -type win10_ltsc = [ - `Ltsc2015 | `Ltsc2016 | `Ltsc2019 | `Ltsc2022 -] [@@deriving sexp] +type win10_ltsc = [ `Ltsc2015 | `Ltsc2016 | `Ltsc2019 | `Ltsc2022 ] +[@@deriving sexp] (** All Windows Long-Term Service Branch releases. LTSC versions are aliased to the semi-annual release they're based on. *) type win_all = [ win10_release | win10_ltsc ] [@@deriving sexp] (** All Windows 10/11 release versions and LTSC names *) -type win10_lcu = [ - | `LCU +type win10_lcu = + [ `LCU | `LCU20220913 | `LCU20220809 | `LCU20220712 @@ -55,8 +64,8 @@ type win10_lcu = [ | `LCU20210914 | `LCU20210810 | `LCU20210713 - | `LCU20210608 -] [@@deriving sexp] + | `LCU20210608 ] +[@@deriving sexp] (** Windows 10 Latest Cumulative Update. Out-of-band LCUs are not included as they aren't released with Docker images. [`LCU] always refers to the most recent LCU. *) @@ -68,32 +77,127 @@ val win10_current_lcu : win10_lcu type win10_revision = win10_release * win10_lcu option [@@deriving sexp] (** A Windows 10 version optionally with an LCU. *) -type distro = [ - | `Alpine of [ `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15 ] +type distro = + [ `Alpine of + [ `V3_3 + | `V3_4 + | `V3_5 + | `V3_6 + | `V3_7 + | `V3_8 + | `V3_9 + | `V3_10 + | `V3_11 + | `V3_12 + | `V3_13 + | `V3_14 + | `V3_15 ] | `Archlinux of [ `Latest ] | `CentOS of [ `V6 | `V7 | `V8 ] | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Testing | `Unstable ] - | `Fedora of [ `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33 | `V34 | `V35 ] + | `Fedora of + [ `V21 + | `V22 + | `V23 + | `V24 + | `V25 + | `V26 + | `V27 + | `V28 + | `V29 + | `V30 + | `V31 + | `V32 + | `V33 + | `V34 + | `V35 ] | `OracleLinux of [ `V7 | `V8 ] | `OpenSUSE of [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 ] - | `Ubuntu of [ `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04 ] + | `Ubuntu of + [ `V12_04 + | `V14_04 + | `V15_04 + | `V15_10 + | `V16_04 + | `V16_10 + | `V17_04 + | `V17_10 + | `V18_04 + | `V18_10 + | `V19_04 + | `V19_10 + | `V20_04 + | `V20_10 + | `V21_04 + | `V21_10 + | `V22_04 ] | `Cygwin of win10_release - | `Windows of [`Mingw | `Msvc] * win10_release -] [@@deriving sexp] + | `Windows of [ `Mingw | `Msvc ] * win10_release ] +[@@deriving sexp] (** Supported Docker container distributions distributions *) -type t = [ - | `Alpine of [ `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15 | `Latest ] +type t = + [ `Alpine of + [ `V3_3 + | `V3_4 + | `V3_5 + | `V3_6 + | `V3_7 + | `V3_8 + | `V3_9 + | `V3_10 + | `V3_11 + | `V3_12 + | `V3_13 + | `V3_14 + | `V3_15 + | `Latest ] | `Archlinux of [ `Latest ] | `CentOS of [ `V6 | `V7 | `V8 | `Latest ] | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Stable | `Testing | `Unstable ] - | `Fedora of [ `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33 | `V34 | `V35 | `Latest ] + | `Fedora of + [ `V21 + | `V22 + | `V23 + | `V24 + | `V25 + | `V26 + | `V27 + | `V28 + | `V29 + | `V30 + | `V31 + | `V32 + | `V33 + | `V34 + | `V35 + | `Latest ] | `OracleLinux of [ `V7 | `V8 | `Latest ] - | `OpenSUSE of [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 | `Latest ] - | `Ubuntu of [ `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04 | `Latest | `LTS ] + | `OpenSUSE of + [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 | `Latest ] + | `Ubuntu of + [ `V12_04 + | `V14_04 + | `V15_04 + | `V15_10 + | `V16_04 + | `V16_10 + | `V17_04 + | `V17_10 + | `V18_04 + | `V18_10 + | `V19_04 + | `V19_10 + | `V20_04 + | `V20_10 + | `V21_04 + | `V21_10 + | `V22_04 + | `Latest + | `LTS ] | `Cygwin of win_all - | `Windows of [`Mingw | `Msvc] * win_all -] [@@deriving sexp] + | `Windows of [ `Mingw | `Msvc ] * win_all ] +[@@deriving sexp] (** Supported Docker container distributions *) type os_family = [ `Cygwin | `Linux | `Windows ] [@@deriving sexp] @@ -156,15 +260,15 @@ val human_readable_short_string_of_distro : t -> string (** [human_readable_short_string_of_distro t] returns a human readable short version of the distribution tag, excluding version information. *) -type package_manager = [ - | `Apk (** Alpine Apk *) +type package_manager = + [ `Apk (** Alpine Apk *) | `Apt (** Debian Apt *) | `Yum (** Fedora Yum *) - | `Zypper (** OpenSUSE Zypper *) - | `Pacman (** Archlinux Pacman *) - | `Cygwin (** Cygwin package manager *) - | `Windows (** Native Windows, WinGet, Cygwin *) -] [@@deriving sexp] + | `Zypper (** OpenSUSE Zypper *) + | `Pacman (** Archlinux Pacman *) + | `Cygwin (** Cygwin package manager *) + | `Windows (** Native Windows, WinGet, Cygwin *) ] +[@@deriving sexp] (** The package manager used by a distro. *) val package_manager : t -> package_manager @@ -192,15 +296,18 @@ val latest_tag_of_distro : t -> string regularly rewritten to point to any new releases of the distribution. *) -type win10_docker_base_image = [ - | `NanoServer (** Windows Nano Server *) - | `ServerCore (** Windows Server Core *) - | `Windows (** Windows Server "with Desktop Experience" *) -] +type win10_docker_base_image = + [ `NanoServer (** Windows Nano Server *) + | `ServerCore (** Windows Server Core *) + | `Windows (** Windows Server "with Desktop Experience" *) ] (** Windows containers base images. @see *) -val win10_base_tag : ?win10_revision:win10_lcu -> win10_docker_base_image -> win_all -> string * string +val win10_base_tag : + ?win10_revision:win10_lcu -> + win10_docker_base_image -> + win_all -> + string * string (** [win10_base_tag base_image release] will return a tuple of Windows container base image and tag for which the base image of a Windows base image can be found (e.g. @@ -208,7 +315,8 @@ val win10_base_tag : ?win10_revision:win10_lcu -> win10_docker_base_image -> win [mcr.microsoft.com/windows/servercore:ltsc2022] on the Microsoft Container Registry). *) -val base_distro_tag : ?win10_revision:win10_lcu -> ?arch:Ocaml_version.arch -> t -> string * string +val base_distro_tag : + ?win10_revision:win10_lcu -> ?arch:Ocaml_version.arch -> t -> string * string (** [base_distro_tag ?arch t] will return a tuple of a Docker Hub user/repository and tag for which the base image of a distribution can be found (e.g. [opensuse/leap],[15.0] which maps to [opensuse/leap:15.0] @@ -225,7 +333,6 @@ val win10_release_of_string : string -> win_all option string to its internal representation. Ignores any KB number. *) val win10_revision_to_string : win10_revision -> string - val win10_revision_of_string : string -> win10_revision option (** {2 CPU architectures} *) @@ -246,8 +353,8 @@ type win10_release_status = [ `Deprecated | `Active ] val win10_release_status : win_all -> win10_release_status (* [win10_release_status v channel] returns the Microsoft support - status of the specified Windows 10 release. - @see *) + status of the specified Windows 10 release. + @see *) val active_distros : Ocaml_version.arch -> t list (** [active_distros arch] returns the list of currently supported diff --git a/src-opam/dockerfile_distro.ml b/src-opam/dockerfile_distro.ml deleted file mode 100644 index 8b45754a..00000000 --- a/src-opam/dockerfile_distro.ml +++ /dev/null @@ -1,1014 +0,0 @@ -(* - * Copyright (c) 2016-2017 Anil Madhavapeddy - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - *) - -(** Distro selection for various OPAM combinations *) -open Astring -open Sexplib.Conv - -type win10_release = [ - | `V1507 | `V1511 | `V1607 | `V1703 | `V1709 | `V1803 | `V1809 - | `V1903 | `V1909 | `V2004 | `V20H2 | `V21H1 | `V21H2 -] [@@deriving sexp] - -type win10_ltsc = [ - `Ltsc2015 | `Ltsc2016 | `Ltsc2019 | `Ltsc2022 -] [@@deriving sexp] - -type win10_lcu = [ - | `LCU - | `LCU20220913 - | `LCU20220809 - | `LCU20220712 - | `LCU20220614 - | `LCU20220510 - | `LCU20220412 - | `LCU20220308 - | `LCU20220208 - | `LCU20220111 - | `LCU20211214 - | `LCU20211109 - | `LCU20211012 - | `LCU20210914 - | `LCU20210810 - | `LCU20210713 - | `LCU20210608 -] [@@deriving sexp] - -type win_all = [ win10_release | win10_ltsc ] [@@deriving sexp] - -let win10_current_lcu = `LCU20220913 - -type win10_revision = win10_release * win10_lcu option [@@deriving sexp] - -let win10_lcus : ('a * int * win10_release list) list = [ - - `LCU20220913, 5017316, [`V21H2]; - `LCU20220913, 5017308, [`V21H1]; - `LCU20220913, 5017315, [`V1809]; - `LCU20220913, 5017305, [`V1607]; - `LCU20220913, 5017327, [`V1507]; - - `LCU20220809, 5016627, [`V21H2]; - `LCU20220809, 5016616, [`V20H2; `V21H1]; - `LCU20220809, 5016623, [`V1809]; - `LCU20220809, 5016622, [`V1607]; - `LCU20220809, 5016639, [`V1507]; - - `LCU20220712, 5015827, [`V21H2]; - `LCU20220712, 5015807, [`V20H2; `V21H1]; - `LCU20220712, 5015811, [`V1809]; - `LCU20220712, 5015808, [`V1607]; - `LCU20220712, 5015832, [`V1507]; - - `LCU20220614, 5014678, [`V21H2]; - `LCU20220614, 5014699, [`V20H2; `V21H1]; - `LCU20220614, 5014692, [`V1809]; - `LCU20220614, 5014702, [`V1607]; - `LCU20220614, 5014710, [`V1507]; - - `LCU20220510, 5013944, [`V21H2]; - `LCU20220510, 5013942, [`V20H2; `V21H1]; - `LCU20220510, 5013945, [`V1909]; - `LCU20220510, 5013941, [`V1809]; - `LCU20220510, 5013952, [`V1607]; - `LCU20220510, 5013963, [`V1507]; - - `LCU20220412, 5012604, [`V21H2]; - `LCU20220412, 5012599, [`V20H2; `V21H1]; - `LCU20220412, 5012591, [`V1909]; - `LCU20220412, 5012647, [`V1809]; - `LCU20220412, 5012596, [`V1607]; - `LCU20220412, 5012653, [`V1507]; - - `LCU20220308, 5011497, [`V21H2]; - `LCU20220308, 5011487, [`V20H2; `V21H1]; - `LCU20220308, 5011485, [`V1909]; - `LCU20220308, 5011503, [`V1809]; - `LCU20220308, 5011495, [`V1607]; - `LCU20220308, 5011491, [`V1507]; - - `LCU20220208, 5010354, [`V21H2]; - `LCU20220208, 5010342, [`V20H2; `V21H1]; - `LCU20220208, 5010345, [`V1909]; - `LCU20220208, 5010351, [`V1809]; - `LCU20220208, 5010359, [`V1607]; - `LCU20220208, 5010358, [`V1507]; - - `LCU20220111, 5009555, [`V21H2]; - `LCU20220111, 5009543, [`V20H2; `V21H1]; - `LCU20220111, 5009545, [`V1909]; - `LCU20220111, 5009557, [`V1809]; - `LCU20220111, 5009546, [`V1607]; - `LCU20220111, 5009585, [`V1507]; - - `LCU20211214, 5008223, [`V21H2]; - `LCU20211214, 5008212, [`V2004; `V20H2; `V21H1]; - `LCU20211214, 5008206, [`V1909]; - `LCU20211214, 5008218, [`V1809]; - `LCU20211214, 5008207, [`V1607]; - `LCU20211214, 5008230, [`V1507]; - - `LCU20211109, 5007205, [`V21H2]; - `LCU20211109, 5007186, [`V2004; `V20H2; `V21H1]; - `LCU20211109, 5007189, [`V1909]; - `LCU20211109, 5007206, [`V1809]; - `LCU20211109, 5007192, [`V1607]; - `LCU20211109, 5007207, [`V1507]; - - `LCU20211012, 5006699, [`V21H2]; - `LCU20211012, 5006670, [`V2004; `V20H2; `V21H1]; - `LCU20211012, 5006667, [`V1909]; - `LCU20211012, 5006672, [`V1809]; - `LCU20211012, 5006669, [`V1607]; - `LCU20211012, 5006675, [`V1507]; - `LCU20210914, 5005575, [`V21H2]; - `LCU20210914, 5005565, [`V2004; `V20H2; `V21H1]; - `LCU20210914, 5005566, [`V1909]; - `LCU20210914, 5005568, [`V1809]; - `LCU20210914, 5005573, [`V1607]; - `LCU20210914, 5005569, [`V1507]; - `LCU20210810, 5005039, [`V21H2]; - `LCU20210810, 5005033, [`V2004; `V20H2; `V21H1]; - `LCU20210810, 5005031, [`V1909]; - `LCU20210810, 5005030, [`V1809]; - `LCU20210810, 5005043, [`V1607]; - `LCU20210810, 5005040, [`V1507]; - `LCU20210713, 5004237, [`V2004; `V20H2; `V21H1]; - `LCU20210713, 5004245, [`V1909]; - `LCU20210713, 5004244, [`V1809]; - `LCU20210713, 5004238, [`V1607]; - `LCU20210713, 5004249, [`V1507]; - `LCU20210608, 5003637, [`V2004; `V20H2; `V21H1]; - `LCU20210608, 5003635, [`V1909]; - `LCU20210608, 5003646, [`V1809]; - `LCU20210608, 5003638, [`V1607]; - `LCU20210608, 5003687, [`V1507]; -] - -let win10_lcu_to_kb : ((win10_lcu * win10_release), int option) Hashtbl.t = - let t = Hashtbl.create 63 in - let f (lcu, kb, vs) = - let g v = - if lcu = win10_current_lcu then - Hashtbl.add t (`LCU, v) (Some kb); - Hashtbl.add t (lcu, v) (Some kb) - in - List.iter g vs in - List.iter f win10_lcus; t - -let win10_kb_to_lcu = - let t = Hashtbl.create 63 in - let f (lcu, kb, vs) = List.iter (fun v -> Hashtbl.add t (kb, v) (Some lcu)) vs in - List.iter f win10_lcus; t - -let win10_lcu_kb_number v lcu = - try Hashtbl.find win10_lcu_to_kb (lcu, v) - with Not_found -> None - -let win10_kb_number_to_lcu (v:win10_release) kb = - match Hashtbl.find win10_kb_to_lcu (kb, v) with - | lcu -> Some (v, lcu) - | exception Not_found -> None - -type distro = [ - | `Alpine of [ `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15 ] - | `Archlinux of [ `Latest ] - | `CentOS of [ `V6 | `V7 | `V8 ] - | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Testing | `Unstable ] - | `Fedora of [ `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33 | `V34 | `V35 ] - | `OracleLinux of [ `V7 | `V8 ] - | `OpenSUSE of [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 ] - | `Ubuntu of [ `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04 ] - | `Cygwin of win10_release - | `Windows of [`Mingw | `Msvc] * win10_release -] [@@deriving sexp] - -type t = [ - | `Alpine of [ `V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15 | `Latest ] - | `Archlinux of [ `Latest ] - | `CentOS of [ `V6 | `V7 | `V8 | `Latest ] - | `Debian of [ `V11 | `V10 | `V9 | `V8 | `V7 | `Stable | `Testing | `Unstable ] - | `Fedora of [ `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33 | `V34 | `V35 | `Latest ] - | `OracleLinux of [ `V7 | `V8 | `Latest ] - | `OpenSUSE of [ `V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3 | `Latest ] - | `Ubuntu of [ `V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04 | `Latest | `LTS ] - | `Cygwin of win_all - | `Windows of [`Mingw | `Msvc] * win_all -] [@@deriving sexp] - -type os_family = [ `Cygwin | `Linux | `Windows ] [@@deriving sexp] - -let os_family_of_distro (t:t) : os_family = - match t with - | `Alpine _ | `Archlinux _ | `CentOS _ | `Debian _ | `Fedora _ - | `OracleLinux _ | `OpenSUSE _ | `Ubuntu _ -> `Linux - | `Cygwin _ -> `Cygwin - | `Windows _ -> `Windows - -let os_family_to_string (os:os_family) = - match os with - | `Linux -> "linux" - | `Windows -> "windows" - | `Cygwin -> "cygwin" - -let opam_repository (os:os_family) = - match os with - | `Cygwin | `Linux -> "https://github.com/ocaml/opam-repository.git" - | `Windows -> "https://github.com/fdopen/opam-repository-mingw.git#opam2" - -let personality os_family arch = - match os_family with - | `Linux when Ocaml_version.arch_is_32bit arch -> Some "/usr/bin/linux32" - | _ -> None - -type status = [ - | `Deprecated - | `Active of [ `Tier1 | `Tier2 | `Tier3 ] - | `Alias - | `Not_available -] [@@deriving sexp] - -let distros : t list = [ - `Alpine `V3_3; `Alpine `V3_4; `Alpine `V3_5; `Alpine `V3_6; `Alpine `V3_7; `Alpine `V3_8; `Alpine `V3_9; `Alpine `V3_10; `Alpine `V3_11; `Alpine `V3_12; `Alpine `V3_13; `Alpine `V3_14; `Alpine `V3_15; `Alpine `Latest; - `Archlinux `Latest; - `CentOS `V6; `CentOS `V7; `CentOS `V8; `CentOS `Latest; - `Debian `V11; `Debian `V10; `Debian `V9; `Debian `V8; `Debian `V7; - `Debian `Stable; `Debian `Testing; `Debian `Unstable; - `Fedora `V23; `Fedora `V24; `Fedora `V25; `Fedora `V26; `Fedora `V27; `Fedora `V28; `Fedora `V29; `Fedora `V30; `Fedora `V31; `Fedora `V32; `Fedora `V33; `Fedora `V34; `Fedora `V35; `Fedora `Latest; - `OracleLinux `V7; `OracleLinux `V8; `OracleLinux `Latest; - `OpenSUSE `V42_1; `OpenSUSE `V42_2; `OpenSUSE `V42_3; `OpenSUSE `V15_0; `OpenSUSE `V15_1; `OpenSUSE `V15_2; `OpenSUSE `V15_3; `OpenSUSE `Latest; - `Ubuntu `V12_04; `Ubuntu `V14_04; `Ubuntu `V15_04; `Ubuntu `V15_10; - `Ubuntu `V16_04; `Ubuntu `V16_10; `Ubuntu `V17_04; `Ubuntu `V17_10; `Ubuntu `V18_04; `Ubuntu `V18_10; `Ubuntu `V19_04; `Ubuntu `V19_10; `Ubuntu `V20_04; `Ubuntu `V20_10; `Ubuntu `V21_04; `Ubuntu `V21_10; `Ubuntu `V22_04; - `Ubuntu `Latest; `Ubuntu `LTS; -] -let distros = - let win10_releases = - [ `V1507; `Ltsc2015; `V1511; `V1607; `Ltsc2016; `V1703; `V1709; `V1809; - `Ltsc2019; `V1903; `V1909; `V2004; `V20H2; `V21H1; `V21H2; `Ltsc2022 ] in - List.fold_left (fun distros version -> - `Cygwin version :: `Windows (`Mingw, version) :: `Windows (`Msvc, version) :: distros) - distros win10_releases - -type win10_release_status = [ `Deprecated | `Active ] - -let resolve_ltsc v = - match v with - | `Ltsc2022 -> `V21H2 - | `Ltsc2019 -> `V1809 - | `Ltsc2016 -> `V1607 - | `Ltsc2015 -> `V1507 - | #win10_release as v -> v - -(* https://en.wikipedia.org/wiki/Windows_10_version_history#Channels *) -let win10_release_status v : win10_release_status = match resolve_ltsc v with - | `V1507 -> `Deprecated | `Ltsc2015 -> `Active - | `V1511 -> `Deprecated - | `V1607 -> `Deprecated | `Ltsc2016 -> `Active - | `V1703 - | `V1709 - | `V1803 - | `V1809 -> `Deprecated | `Ltsc2019 -> `Active - | `V1903 - | `V1909 -> `Deprecated - | `V2004 -> `Deprecated - | `V20H2 -> `Deprecated - | `V21H1 | `V21H2 | `Ltsc2022 -> `Active - -let win10_latest_release = `V21H2 - -type win10_docker_base_image = [ `Windows | `ServerCore | `NanoServer ] - -(* https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle *) -let win10_docker_status (base : win10_docker_base_image) v : status = - match base, v with - | _, `V21H2 -> `Active `Tier3 - | _, `V20H2 - | _, `V2004 - | _, `V1909 - | _, `V1903 -> `Deprecated - | `ServerCore, `V1809 - | `NanoServer, `V1809 - | `Windows, `V1809 -> `Active `Tier3 - | (`ServerCore | `NanoServer), `V1803 - | (`ServerCore | `NanoServer), `V1709 -> `Deprecated - | `ServerCore, `V1607 -> `Active `Tier3 - | `NanoServer, `V1607 -> `Deprecated - | _ -> `Not_available - -let win10_latest_image = `V21H2 - -let resolve_alias (d:t) : distro = - match d with - | `Alpine `Latest -> `Alpine `V3_15 - | `CentOS `Latest -> `CentOS `V7 - | `Debian `Stable -> `Debian `V11 - | `Fedora `Latest -> `Fedora `V35 - | `OracleLinux `Latest -> `OracleLinux `V8 - | `OpenSUSE `Latest -> `OpenSUSE `V15_3 - | `Ubuntu `Latest -> `Ubuntu `V22_04 - | `Ubuntu `LTS -> `Ubuntu `V22_04 - | `Cygwin (#win10_ltsc as v) -> `Cygwin (resolve_ltsc v) - | `Windows (cc, (#win10_ltsc as v)) -> `Windows (cc, resolve_ltsc v) - | `Alpine (`V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15) - | `Archlinux `Latest - | `CentOS (`V6 | `V7 | `V8) - | `Debian (`V7 | `V8 | `V9 | `V10 | `V11 | `Testing | `Unstable) - | `Fedora (`V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33 | `V34 | `V35) - | `OracleLinux (`V7 | `V8) - | `OpenSUSE (`V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2 | `V15_3) - | `Ubuntu (`V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_04 | `V18_10 | `V19_04 | `V19_10 | `V20_04 | `V20_10 | `V21_04 | `V21_10 | `V22_04) - | `Cygwin (`V1507 | `V1511 | `V1607 | `V1703 | `V1709 | `V1803 | `V1809 | `V1903 | `V1909 | `V2004 | `V20H2 | `V21H1 | `V21H2) - | `Windows (_, (`V1507 | `V1511 | `V1607 | `V1703 | `V1709 | `V1803 | `V1809 | `V1903 | `V1909 | `V2004 | `V20H2 | `V21H1 | `V21H2)) as d -> - d - -let distro_status (d:t) : status = - let resolved = resolve_alias d in - if (resolved : distro :> t) <> d then - `Alias - else - match resolve_alias d with - | `Alpine (`V3_3 | `V3_4 | `V3_5 | `V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 |`V3_13) -> `Deprecated - | `Alpine `V3_14 -> `Active `Tier2 - | `Alpine `V3_15 -> `Active `Tier1 - | `Archlinux `Latest -> `Active `Tier3 - | `CentOS `V7 -> `Active `Tier3 - | `CentOS (`V6|`V8) -> `Deprecated - | `Debian (`V7|`V8|`V9) -> `Deprecated - | `Debian `V10 -> `Active `Tier2 - | `Debian `V11 -> `Active `Tier1 - | `Debian `Testing -> `Active `Tier3 - | `Debian `Unstable -> `Active `Tier3 - | `Fedora ( `V21 | `V22 | `V23 | `V24 | `V25 | `V26 | `V27 | `V28 | `V29 | `V30 | `V31 | `V32 | `V33) -> `Deprecated - | `Fedora (`V34 | `V35) -> `Active `Tier2 - | `OracleLinux (`V7|`V8) -> `Active `Tier3 - | `OpenSUSE (`V42_1 | `V42_2 | `V42_3 | `V15_0 | `V15_1 | `V15_2) -> `Deprecated - | `OpenSUSE `V15_3 -> `Active `Tier2 - | `Ubuntu (`V18_04) -> `Active `Tier3 - | `Ubuntu (`V20_04 | `V22_04) -> `Active `Tier2 - | `Ubuntu (`V12_04 | `V14_04 | `V15_04 | `V15_10 | `V16_04 | `V16_10 | `V17_04 | `V17_10 | `V18_10 | `V19_04 | `V19_10 | `V20_10 | `V21_04 | `V21_10) -> `Deprecated - | `Cygwin v -> win10_docker_status `ServerCore v - | `Windows (_, v) -> win10_docker_status `Windows v - -let latest_distros = - [ `Alpine `Latest; `Archlinux `Latest; `CentOS `Latest; - `Debian `Stable; `OracleLinux `Latest; `OpenSUSE `Latest; - `Fedora `Latest; `Ubuntu `Latest; `Ubuntu `LTS; - (* Prefer win10_latest_image to win10_latest_release as - latest_distro is used by docker-base-images to fetch tag - aliases. *) - `Cygwin win10_latest_image; - `Windows (`Mingw, win10_latest_image); - `Windows (`Msvc, win10_latest_image); - ] - -let master_distro = `Debian `Stable - -module OV = Ocaml_version - -let distro_arches ov (d:t) = - match resolve_alias d, ov with - | `Windows (`Msvc, _), ov when OV.major ov >= 5 -> [] - | (`CentOS (`V6|`V7)|`OracleLinux `V7), ov when OV.major ov >= 5 -> [] - | `Debian `V11, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> [ `I386; `X86_64; `Aarch64; `Aarch32; `Ppc64le; `S390x ] - | `Debian `V11, ov when OV.(compare Releases.v4_02_0 ov) = -1 -> [ `I386; `X86_64; `Aarch64; `Aarch32] - | `Debian `V10, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> [ `I386; `X86_64; `Aarch64; `Aarch32; `Ppc64le; `S390x ] - | `Debian `V10, ov when OV.(compare Releases.v4_02_0 ov) = -1 -> [ `I386; `X86_64; `Aarch64; `Aarch32] - | `Debian `V9, ov when OV.(compare Releases.v4_03_0 ov) = -1 -> [ `I386; `X86_64; `Aarch64; `Aarch32 ] - | `Alpine (`V3_6 | `V3_7 | `V3_8 | `V3_9 | `V3_10 | `V3_11 | `V3_12 | `V3_13 | `V3_14 | `V3_15), ov when OV.(compare Releases.v4_05_0 ov) = -1 -> [ `X86_64; `Aarch64 ] - | `Ubuntu `V18_04, ov when OV.(compare Releases.v4_05_0 ov) = -1 -> [ `X86_64; `Aarch64; `Ppc64le; `S390x ] - | `Ubuntu (`V20_04|`V20_10|`V21_04|`V21_10|`V22_04), ov when OV.(compare Releases.v4_05_0 ov) = -1 -> - let base = [ `X86_64; `Aarch64; `Ppc64le; `S390x ] in - if OV.(compare Releases.v4_11_0 ov) <= 0 then - `Riscv64 :: base - else - base - | `Fedora (`V33|`V34|`V35), ov when OV.(compare Releases.v4_08_0 ov) = -1 -> [ `X86_64; `Aarch64 ] - (* 2021-04-19: should be 4.03 but there's a linking failure until 4.06. *) - | `Windows (`Msvc, _), ov when OV.(compare Releases.v4_06_0 ov) = 1 -> [] - | _ -> [ `X86_64 ] - - -let distro_supported_on a ov (d:t) = - List.mem a (distro_arches ov d) - -let distro_active_for arch (d:t) = - match arch, d with - | `X86_64, `Windows _ -> true - | _ -> distro_supported_on arch OV.Releases.latest d - -let active_distros arch = - List.filter (fun d -> match distro_status d with `Active _ -> true | _ -> false ) distros |> - List.filter (distro_active_for arch) - -let active_tier1_distros arch = - List.filter (fun d -> match distro_status d with `Active `Tier1 -> true | _ -> false ) distros |> - List.filter (distro_active_for arch) - -let active_tier2_distros arch = - List.filter (fun d -> match distro_status d with `Active `Tier2 -> true | _ -> false ) distros |> - List.filter (distro_active_for arch) - -let active_tier3_distros arch = - List.filter (fun d -> match distro_status d with `Active `Tier3 -> true | _ -> false ) distros |> - List.filter (distro_active_for arch) - -(* The distro-supplied version of OCaml *) -let builtin_ocaml_of_distro (d:t) : string option = - match resolve_alias d with - |`Debian `V7 -> Some "3.12.1" - |`Debian `V8 -> Some "4.01.0" - |`Debian `V9 -> Some "4.02.3" - |`Debian `V10 -> Some "4.05.0" - |`Debian `V11 -> Some "4.11.1" - |`Ubuntu `V12_04 -> Some "3.12.1" - |`Ubuntu `V14_04 -> Some "4.01.0" - |`Ubuntu `V15_04 -> Some "4.01.0" - |`Ubuntu `V15_10 -> Some "4.01.0" - |`Ubuntu `V16_04 -> Some "4.02.3" - |`Ubuntu `V16_10 -> Some "4.02.3" - |`Ubuntu `V17_04 -> Some "4.02.3" - |`Ubuntu `V17_10 -> Some "4.04.0" - |`Ubuntu `V18_04 -> Some "4.05.0" - |`Ubuntu `V18_10 -> Some "4.05.0" - |`Ubuntu `V19_04 -> Some "4.05.0" - |`Ubuntu `V19_10 -> Some "4.05.0" - |`Ubuntu `V20_04 -> Some "4.08.1" - |`Ubuntu `V20_10 -> Some "4.08.1" - |`Ubuntu `V21_04 -> Some "4.11.1" - |`Ubuntu `V21_10 -> Some "4.11.1" - |`Ubuntu `V22_04 -> failwith "4.11.1; not yet confirmed" - |`Alpine `V3_3 -> Some "4.02.3" - |`Alpine `V3_4 -> Some "4.02.3" - |`Alpine `V3_5 -> Some "4.04.0" - |`Alpine `V3_6 -> Some "4.04.1" - |`Alpine `V3_7 -> Some "4.04.2" - |`Alpine `V3_8 -> Some "4.06.1" - |`Alpine `V3_9 -> Some "4.06.1" - |`Alpine `V3_10 -> Some "4.07.0" - |`Alpine `V3_11 -> Some "4.08.1" - |`Alpine `V3_12 -> Some "4.08.1" - |`Alpine `V3_13 -> Some "4.08.1" - |`Alpine `V3_14 -> Some "4.12.0" - |`Alpine `V3_15 -> Some "4.13.1" - |`Archlinux `Latest -> Some "4.11.1" - |`Fedora `V21 -> Some "4.01.0" - |`Fedora `V22 -> Some "4.02.0" - |`Fedora `V23 -> Some "4.02.2" - |`Fedora `V24 -> Some "4.02.3" - |`Fedora `V25 -> Some "4.02.3" - |`Fedora `V26 -> Some "4.04.0" - |`Fedora `V27 -> Some "4.05.0" - |`Fedora `V28 -> Some "4.06.0" - |`Fedora `V29 -> Some "4.07.0" - |`Fedora `V30 -> Some "4.07.0" - |`Fedora `V31 -> Some "4.08.1" - |`Fedora `V32 -> Some "4.10.0" - |`Fedora `V33 -> Some "4.11.1" - |`Fedora `V34 -> Some "4.11.1" - |`Fedora `V35 -> Some "4.12.0" - |`CentOS `V6 -> Some "3.11.2" - |`CentOS `V7 -> Some "4.01.0" - |`CentOS `V8 -> Some "4.07.0" - |`OpenSUSE `V42_1 -> Some "4.02.3" - |`OpenSUSE `V42_2 -> Some "4.03.0" - |`OpenSUSE `V42_3 -> Some "4.03.0" - |`OpenSUSE `V15_0 -> Some "4.05.0" - |`OpenSUSE `V15_1 -> Some "4.05.0" - |`OpenSUSE `V15_2 -> Some "4.05.0" - |`OpenSUSE `V15_3 -> Some "4.05.0" - |`OracleLinux `V7 -> Some "4.01.0" - |`OracleLinux `V8 -> Some "4.07.0" - |`Cygwin _ -> None - |`Windows _ -> None - |`Debian (`Testing | `Unstable) -> assert false - -let win10_release_to_string = function - | `V1507 -> "1507" | `Ltsc2015 -> "ltsc2015" | `V1511 -> "1511" - | `V1607 -> "1607" | `Ltsc2016 -> "ltsc2016" | `V1703 -> "1703" - | `V1709 -> "1709" | `V1803 -> "1803" | `V1809 -> "1809" - | `Ltsc2019 -> "ltsc2019" | `V1903 -> "1903" | `V1909 -> "1909" - | `V2004 -> "2004" | `V20H2 -> "20H2" | `V21H1 -> "21H1" - | `Ltsc2022 -> "ltsc2022" | `V21H2 -> "21H2" - -let win10_release_of_string v : win_all option = - let v = match String.cut ~sep:"-KB" v with - | Some (v, kb) -> if String.for_all Char.Ascii.is_digit kb then v else "" - | None -> v - in - match v with - | "1507" -> Some `V1507 | "ltsc2015" -> Some `Ltsc2015 | "1511" -> Some `V1511 - | "1607" -> Some `V1607 | "ltsc2016" -> Some `Ltsc2016 | "1703" -> Some `V1703 - | "1709" -> Some `V1709 | "1803" -> Some `V1803 | "1809" -> Some `V1809 - | "ltsc2019" -> Some `Ltsc2019 | "1903" -> Some `V1903 | "1909" -> Some `V1909 - | "2004" -> Some `V2004 | "20H2" -> Some `V20H2 | "21H1" -> Some `V21H1 - | "ltsc2022" -> Some `Ltsc2022 - | _ -> None - -let rec win10_revision_to_string = function -| (v, None) -> win10_release_to_string v -| (v, Some `LCU) -> win10_revision_to_string (v, Some win10_current_lcu) -| (v, Some lcu) -> - match win10_lcu_kb_number (resolve_ltsc v) lcu with - | Some kb -> Printf.sprintf "%s-KB%d" (win10_release_to_string v) kb - | None -> Fmt.invalid_arg "No KB for this Win10 %s revision" (win10_release_to_string v) - -let win10_revision_of_string v = - let v, lcu = - match String.cut ~sep:"-KB" v with - | Some (v, lcu) when String.for_all Char.Ascii.is_digit lcu -> - (v, Some (int_of_string lcu)) - | _ -> - (v, None) - in - match win10_release_of_string v with - | None -> None - | Some v -> - let v = resolve_ltsc v in - match lcu with - | None -> Some (v, None) - | Some lcu -> win10_kb_number_to_lcu v lcu - -(* The Docker tag for this distro *) -let tag_of_distro (d:t) = match d with - |`Ubuntu `V12_04 -> "ubuntu-12.04" - |`Ubuntu `V14_04 -> "ubuntu-14.04" - |`Ubuntu `V15_04 -> "ubuntu-15.04" - |`Ubuntu `V15_10 -> "ubuntu-15.10" - |`Ubuntu `V16_04 -> "ubuntu-16.04" - |`Ubuntu `V16_10 -> "ubuntu-16.10" - |`Ubuntu `V17_04 -> "ubuntu-17.04" - |`Ubuntu `V17_10 -> "ubuntu-17.10" - |`Ubuntu `V18_04 -> "ubuntu-18.04" - |`Ubuntu `V18_10 -> "ubuntu-18.10" - |`Ubuntu `V19_04 -> "ubuntu-19.04" - |`Ubuntu `V19_10 -> "ubuntu-19.10" - |`Ubuntu `V20_04 -> "ubuntu-20.04" - |`Ubuntu `V20_10 -> "ubuntu-20.10" - |`Ubuntu `V21_04 -> "ubuntu-21.04" - |`Ubuntu `V21_10 -> "ubuntu-21.10" - |`Ubuntu `V22_04 -> "ubuntu-22.04" - |`Ubuntu `Latest -> "ubuntu" - |`Ubuntu `LTS -> "ubuntu-lts" - |`Debian `Stable -> "debian-stable" - |`Debian `Unstable -> "debian-unstable" - |`Debian `Testing -> "debian-testing" - |`Debian `V11 -> "debian-11" - |`Debian `V10 -> "debian-10" - |`Debian `V9 -> "debian-9" - |`Debian `V8 -> "debian-8" - |`Debian `V7 -> "debian-7" - |`CentOS `V6 -> "centos-6" - |`CentOS `V7 -> "centos-7" - |`CentOS `V8 -> "centos-8" - |`CentOS `Latest -> "centos" - |`Fedora `Latest -> "fedora" - |`Fedora `V21 -> "fedora-21" - |`Fedora `V22 -> "fedora-22" - |`Fedora `V23 -> "fedora-23" - |`Fedora `V24 -> "fedora-24" - |`Fedora `V25 -> "fedora-25" - |`Fedora `V26 -> "fedora-26" - |`Fedora `V27 -> "fedora-27" - |`Fedora `V28 -> "fedora-28" - |`Fedora `V29 -> "fedora-29" - |`Fedora `V30 -> "fedora-30" - |`Fedora `V31 -> "fedora-31" - |`Fedora `V32 -> "fedora-32" - |`Fedora `V33 -> "fedora-33" - |`Fedora `V34 -> "fedora-34" - |`Fedora `V35 -> "fedora-35" - |`OracleLinux `V7 -> "oraclelinux-7" - |`OracleLinux `V8 -> "oraclelinux-8" - |`OracleLinux `Latest -> "oraclelinux" - |`Alpine `V3_3 -> "alpine-3.3" - |`Alpine `V3_4 -> "alpine-3.4" - |`Alpine `V3_5 -> "alpine-3.5" - |`Alpine `V3_6 -> "alpine-3.6" - |`Alpine `V3_7 -> "alpine-3.7" - |`Alpine `V3_8 -> "alpine-3.8" - |`Alpine `V3_9 -> "alpine-3.9" - |`Alpine `V3_10 -> "alpine-3.10" - |`Alpine `V3_11 -> "alpine-3.11" - |`Alpine `V3_12 -> "alpine-3.12" - |`Alpine `V3_13 -> "alpine-3.13" - |`Alpine `V3_14 -> "alpine-3.14" - |`Alpine `V3_15 -> "alpine-3.15" - |`Alpine `Latest -> "alpine" - |`Archlinux `Latest -> "archlinux" - |`OpenSUSE `V42_1 -> "opensuse-42.1" - |`OpenSUSE `V42_2 -> "opensuse-42.2" - |`OpenSUSE `V42_3 -> "opensuse-42.3" - |`OpenSUSE `V15_0 -> "opensuse-15.0" - |`OpenSUSE `V15_1 -> "opensuse-15.1" - |`OpenSUSE `V15_2 -> "opensuse-15.2" - |`OpenSUSE `V15_3 -> "opensuse-15.3" - |`OpenSUSE `Latest -> "opensuse" - |`Cygwin v -> "cygwin-" ^ (win10_release_to_string v) - |`Windows (`Mingw, v) -> "windows-mingw-" ^ (win10_release_to_string v) - |`Windows (`Msvc, v) -> "windows-msvc-" ^ (win10_release_to_string v) - -let distro_of_tag x : t option = - let win10_of_tag affix s f = - let stop = String.length affix in - match win10_release_of_string (String.(sub ~start:0 ~stop s |> Sub.to_string)) with - | Some v -> Some (f v) - | None -> None - in - match x with - |"ubuntu-12.04" -> Some (`Ubuntu `V12_04) - |"ubuntu-14.04" -> Some (`Ubuntu `V14_04) - |"ubuntu-15.04" -> Some (`Ubuntu `V15_04) - |"ubuntu-15.10" -> Some (`Ubuntu `V15_10) - |"ubuntu-16.04" -> Some (`Ubuntu `V16_04) - |"ubuntu-16.10" -> Some (`Ubuntu `V16_10) - |"ubuntu-17.04" -> Some (`Ubuntu `V17_04) - |"ubuntu-17.10" -> Some (`Ubuntu `V17_10) - |"ubuntu-18.04" -> Some (`Ubuntu `V18_04) - |"ubuntu-18.10" -> Some (`Ubuntu `V18_10) - |"ubuntu-19.04" -> Some (`Ubuntu `V19_04) - |"ubuntu-19.10" -> Some (`Ubuntu `V19_10) - |"ubuntu-20.04" -> Some (`Ubuntu `V20_04) - |"ubuntu-20.10" -> Some (`Ubuntu `V20_10) - |"ubuntu-21.04" -> Some (`Ubuntu `V21_04) - |"ubuntu-21.10" -> Some (`Ubuntu `V21_10) - |"ubuntu-22.04" -> Some (`Ubuntu `V22_04) - |"ubuntu" -> Some (`Ubuntu `Latest) - |"ubuntu-lts" -> Some (`Ubuntu `LTS) - |"debian-stable" -> Some (`Debian `Stable) - |"debian-unstable" -> Some (`Debian `Unstable) - |"debian-testing" -> Some (`Debian `Testing) - |"debian-11" -> Some (`Debian `V11) - |"debian-10" -> Some (`Debian `V10) - |"debian-9" -> Some (`Debian `V9) - |"debian-8" -> Some (`Debian `V8) - |"debian-7" -> Some (`Debian `V7) - |"centos-6" -> Some (`CentOS `V6) - |"centos-7" -> Some (`CentOS `V7) - |"centos-8" -> Some (`CentOS `V8) - |"fedora-21" -> Some (`Fedora `V21) - |"fedora-22" -> Some (`Fedora `V22) - |"fedora-23" -> Some (`Fedora `V23) - |"fedora-24" -> Some (`Fedora `V24) - |"fedora-25" -> Some (`Fedora `V25) - |"fedora-26" -> Some (`Fedora `V26) - |"fedora-27" -> Some (`Fedora `V27) - |"fedora-28" -> Some (`Fedora `V28) - |"fedora-29" -> Some (`Fedora `V29) - |"fedora-30" -> Some (`Fedora `V30) - |"fedora-31" -> Some (`Fedora `V31) - |"fedora-32" -> Some (`Fedora `V32) - |"fedora-33" -> Some (`Fedora `V33) - |"fedora-34" -> Some (`Fedora `V34) - |"fedora-35" -> Some (`Fedora `V35) - |"fedora" -> Some (`Fedora `Latest) - |"oraclelinux-7" -> Some (`OracleLinux `V7) - |"oraclelinux-8" -> Some (`OracleLinux `V8) - |"oraclelinux" -> Some (`OracleLinux `Latest) - |"alpine-3.3" -> Some (`Alpine `V3_3) - |"alpine-3.4" -> Some (`Alpine `V3_4) - |"alpine-3.5" -> Some (`Alpine `V3_5) - |"alpine-3.6" -> Some (`Alpine `V3_6) - |"alpine-3.7" -> Some (`Alpine `V3_7) - |"alpine-3.8" -> Some (`Alpine `V3_8) - |"alpine-3.9" -> Some (`Alpine `V3_9) - |"alpine-3.10" -> Some (`Alpine `V3_10) - |"alpine-3.11" -> Some (`Alpine `V3_11) - |"alpine-3.12" -> Some (`Alpine `V3_12) - |"alpine-3.13" -> Some (`Alpine `V3_13) - |"alpine-3.14" -> Some (`Alpine `V3_14) - |"alpine-3.15" -> Some (`Alpine `V3_15) - |"alpine" -> Some (`Alpine `Latest) - |"archlinux" -> Some (`Archlinux `Latest) - |"opensuse-42.1" -> Some (`OpenSUSE `V42_1) - |"opensuse-42.2" -> Some (`OpenSUSE `V42_2) - |"opensuse-42.3" -> Some (`OpenSUSE `V42_3) - |"opensuse-15.0" -> Some (`OpenSUSE `V15_0) - |"opensuse-15.1" -> Some (`OpenSUSE `V15_1) - |"opensuse-15.2" -> Some (`OpenSUSE `V15_2) - |"opensuse-15.3" -> Some (`OpenSUSE `V15_3) - |"opensuse" -> Some (`OpenSUSE `Latest) - | s when String.is_prefix ~affix:"cygwin-" s -> - win10_of_tag "cygwin-" s (fun v -> `Cygwin v) - | s when String.is_prefix ~affix:"windows-mingw-" s -> - win10_of_tag "windows-mingw-" s (fun v -> `Windows (`Mingw, v)) - | s when String.is_prefix ~affix:"windows-msvc-" s -> - win10_of_tag "windows-msvc-" s (fun v -> `Windows (`Msvc, v)) - |_ -> None - -let human_readable_string_of_distro (d:t) = - if d = `Debian `Stable then - "Debian Stable" - else - match resolve_alias d with - |`Ubuntu `V12_04 -> "Ubuntu 12.04" - |`Ubuntu `V14_04 -> "Ubuntu 14.04" - |`Ubuntu `V15_04 -> "Ubuntu 15.04" - |`Ubuntu `V15_10 -> "Ubuntu 15.10" - |`Ubuntu `V16_04 -> "Ubuntu 16.04" - |`Ubuntu `V16_10 -> "Ubuntu 16.10" - |`Ubuntu `V17_04 -> "Ubuntu 17.04" - |`Ubuntu `V17_10 -> "Ubuntu 17.10" - |`Ubuntu `V18_04 -> "Ubuntu 18.04" - |`Ubuntu `V18_10 -> "Ubuntu 18.10" - |`Ubuntu `V19_04 -> "Ubuntu 19.04" - |`Ubuntu `V19_10 -> "Ubuntu 19.10" - |`Ubuntu `V20_04 -> "Ubuntu 20.04" - |`Ubuntu `V20_10 -> "Ubuntu 20.10" - |`Ubuntu `V21_04 -> "Ubuntu 21.04" - |`Ubuntu `V21_10 -> "Ubuntu 21.10" - |`Ubuntu `V22_04 -> "Ubuntu 22.04" - |`Debian `Unstable -> "Debian Unstable" - |`Debian `Testing -> "Debian Testing" - |`Debian `V11 -> "Debian 11 (Bullseye)" - |`Debian `V10 -> "Debian 10 (Buster)" - |`Debian `V9 -> "Debian 9 (Stretch)" - |`Debian `V8 -> "Debian 8 (Jessie)" - |`Debian `V7 -> "Debian 7 (Wheezy)" - |`CentOS `V6 -> "CentOS 6" - |`CentOS `V7 -> "CentOS 7" - |`CentOS `V8 -> "CentOS 8" - |`Fedora `V21 -> "Fedora 21" - |`Fedora `V22 -> "Fedora 22" - |`Fedora `V23 -> "Fedora 23" - |`Fedora `V24 -> "Fedora 24" - |`Fedora `V25 -> "Fedora 25" - |`Fedora `V26 -> "Fedora 26" - |`Fedora `V27 -> "Fedora 27" - |`Fedora `V28 -> "Fedora 28" - |`Fedora `V29 -> "Fedora 29" - |`Fedora `V30 -> "Fedora 30" - |`Fedora `V31 -> "Fedora 31" - |`Fedora `V32 -> "Fedora 32" - |`Fedora `V33 -> "Fedora 33" - |`Fedora `V34 -> "Fedora 34" - |`Fedora `V35 -> "Fedora 35" - |`OracleLinux `V7 -> "OracleLinux 7" - |`OracleLinux `V8 -> "OracleLinux 8" - |`Alpine `V3_3 -> "Alpine 3.3" - |`Alpine `V3_4 -> "Alpine 3.4" - |`Alpine `V3_5 -> "Alpine 3.5" - |`Alpine `V3_6 -> "Alpine 3.6" - |`Alpine `V3_7 -> "Alpine 3.7" - |`Alpine `V3_8 -> "Alpine 3.8" - |`Alpine `V3_9 -> "Alpine 3.9" - |`Alpine `V3_10 -> "Alpine 3.10" - |`Alpine `V3_11 -> "Alpine 3.11" - |`Alpine `V3_12 -> "Alpine 3.12" - |`Alpine `V3_13 -> "Alpine 3.13" - |`Alpine `V3_14 -> "Alpine 3.14" - |`Alpine `V3_15 -> "Alpine 3.15" - |`Archlinux `Latest -> "Archlinux" - |`OpenSUSE `V42_1 -> "OpenSUSE 42.1" - |`OpenSUSE `V42_2 -> "OpenSUSE 42.2" - |`OpenSUSE `V42_3 -> "OpenSUSE 42.3" - |`OpenSUSE `V15_0 -> "OpenSUSE 15.0 (Leap)" - |`OpenSUSE `V15_1 -> "OpenSUSE 15.1 (Leap)" - |`OpenSUSE `V15_2 -> "OpenSUSE 15.2 (Leap)" - |`OpenSUSE `V15_3 -> "OpenSUSE 15.3 (Leap)" - |`Cygwin v -> "Cygwin " ^ (win10_release_to_string v) - |`Windows (`Mingw, v) -> "Windows mingw " ^ (win10_release_to_string v) - |`Windows (`Msvc, v) -> "Windows mingw " ^ (win10_release_to_string v) - -let human_readable_short_string_of_distro (t:t) = - match t with - |`Ubuntu _ -> "Ubuntu" - |`Debian _ -> "Debian" - |`CentOS _ -> "CentOS" - |`Fedora _ -> "Fedora" - |`OracleLinux _ -> "OracleLinux" - |`Alpine _ -> "Alpine" - |`Archlinux _ -> "Archlinux" - |`OpenSUSE _ -> "OpenSUSE" - |`Cygwin _ -> "Cygwin" - |`Windows (`Mingw, _) -> "Windows mingw" - |`Windows (`Msvc, _) -> "Windows mvsc" - -let is_same_distro (d1:t) (d2:t) = - match d1, d2 with - | `Ubuntu _, `Ubuntu _ | `Debian _, `Debian _ | `CentOS _, `CentOS _ - | `Fedora _, `Fedora _ | `OracleLinux _, `OracleLinux _ - | `Alpine _, `Alpine _ | `Archlinux _, `Archlinux _ - | `OpenSUSE _, `OpenSUSE _ | `Cygwin _, `Cygwin _ -> true - | `Windows (p1, _), `Windows (p2, _) when p1 = p2 -> true - | _ -> false - -(* The alias tag for the latest stable version of this distro *) -let latest_tag_of_distro (t:t) = - let latest = List.find (is_same_distro t) latest_distros in - tag_of_distro latest - -type package_manager = [ `Apt | `Yum | `Apk | `Zypper | `Pacman | `Cygwin | `Windows ] [@@deriving sexp] - -let package_manager (t:t) = - match t with - |`Ubuntu _ -> `Apt - |`Debian _ -> `Apt - |`CentOS _ -> `Yum - |`Fedora _ -> `Yum - |`OracleLinux _ -> `Yum - |`Alpine _ -> `Apk - |`Archlinux _ -> `Pacman - |`OpenSUSE _ -> `Zypper - |`Cygwin _ -> `Cygwin - |`Windows _ -> `Windows - -let rec bubblewrap_version (t:t) = - match resolve_alias t with - | `Ubuntu `V12_04 -> None - | `Ubuntu `V14_04 -> None - | `Ubuntu `V15_04 -> None - | `Ubuntu `V15_10 -> None - | `Ubuntu `V16_04 -> None - | `Ubuntu `V16_10 -> None (* Not actually checked *) - | `Ubuntu `V17_04 -> None (* Not actually checked *) - | `Ubuntu `V17_10 -> None (* Not actually checked *) - | `Ubuntu `V18_04 -> Some (0, 2, 1) - | `Ubuntu `V18_10 -> Some (0, 2, 1) (* Not actually checked *) - | `Ubuntu `V19_04 -> Some (0, 2, 1) (* Not actually checked *) - | `Ubuntu `V19_10 -> Some (0, 2, 1) (* Not actually checked *) - | `Ubuntu `V20_04 -> Some (0, 4, 0) - | `Ubuntu `V20_10 -> Some (0, 4, 0) (* Not actually checked *) - | `Ubuntu `V21_04 -> Some (0, 4, 1) - | `Ubuntu `V21_10 -> Some (0, 4, 1) - | `Ubuntu `V22_04 -> Some (0, 5, 0) - | `Debian `V7 -> None (* Not actually checked *) - | `Debian `V8 -> None (* Not actually checked *) - | `Debian `V9 -> Some (0, 3, 1) - | `Debian `V10 -> Some (0, 3, 1) - | `Debian `V11 -> Some (0, 4, 1) - | `Debian `Testing -> Some (0, 5, 0) - | `Debian `Unstable -> Some (0, 5, 0) - | `CentOS `V6 -> None - | `CentOS `V7 -> None - | `CentOS `V8 -> Some (0, 4, 0) - | `Fedora `V21 -> None (* Not actually checked *) - | `Fedora `V22 -> None (* Not actually checked *) - | `Fedora `V23 -> None (* Not actually checked *) - | `Fedora `V24 -> None (* Not actually checked *) - | `Fedora `V25 -> None (* Not actually checked *) - | `Fedora `V26 -> Some (0, 2, 0) - | `Fedora `V27 -> Some (0, 2, 1) - | `Fedora `V28 -> Some (0, 3, 0) - | `Fedora `V29 -> Some (0, 3, 1) - | `Fedora `V30 -> Some (0, 3, 3) - | `Fedora `V31 -> Some (0, 4, 1) - | `Fedora `V32 -> Some (0, 4, 1) - | `Fedora `V33 -> Some (0, 4, 1) - | `Fedora `V34 -> Some (0, 4, 1) - | `Fedora `V35 -> Some (0, 5, 0) - | `OracleLinux (`V7|`V8 as v) -> bubblewrap_version (`CentOS v) - | `Alpine `V3_3 -> None (* Not actually checked *) - | `Alpine `V3_4 -> None (* Not actually checked *) - | `Alpine `V3_5 -> None (* Not actually checked *) - | `Alpine `V3_6 -> None (* Not actually checked *) - | `Alpine `V3_7 -> None (* Not actually checked *) - | `Alpine `V3_8 -> Some (0, 2, 0) - | `Alpine `V3_9 -> Some (0, 3, 1) - | `Alpine `V3_10 -> Some (0, 3, 3) - | `Alpine `V3_11 -> Some (0, 4, 1) - | `Alpine `V3_12 -> Some (0, 4, 1) - | `Alpine `V3_13 -> Some (0, 4, 1) - | `Alpine `V3_14 -> Some (0, 4, 1) - | `Alpine `V3_15 -> Some (0, 5, 0) - | `Archlinux `Latest -> Some (0, 5, 0) - | `OpenSUSE `V42_1 -> None (* Not actually checked *) - | `OpenSUSE `V42_2 -> None (* Not actually checked *) - | `OpenSUSE `V42_3 -> None (* Not actually checked *) - | `OpenSUSE `V15_0 -> Some (0, 2, 0) - | `OpenSUSE `V15_1 -> Some (0, 3, 3) - | `OpenSUSE `V15_2 -> Some (0, 4, 1) - | `OpenSUSE `V15_3 -> Some (0, 4, 1) - | `Cygwin _ -> None - | `Windows _ -> None - -let win10_base_tag ?win10_revision (base:win10_docker_base_image) v = - let base, v = match base, resolve_ltsc v with - | `NanoServer, _ -> "mcr.microsoft.com/windows/nanoserver", v - | `ServerCore, _ -> "mcr.microsoft.com/windows/servercore", v - | `Windows, `V21H2 -> "mcr.microsoft.com/windows/server", `Ltsc2022 - | `Windows, _ -> "mcr.microsoft.com/windows", v in - base, win10_revision_to_string (v, win10_revision) - -let base_distro_tag ?win10_revision ?(arch=`X86_64) d = - match resolve_alias d with - | `Alpine v -> begin - let tag = - match v with - | `V3_3 -> "3.3" - | `V3_4 -> "3.4" - | `V3_5 -> "3.5" - | `V3_6 -> "3.6" - | `V3_7 -> "3.7" - | `V3_8 -> "3.8" - | `V3_9 -> "3.9" - | `V3_10 -> "3.10" - | `V3_11 -> "3.11" - | `V3_12 -> "3.12" - | `V3_13 -> "3.13" - | `V3_14 -> "3.14" - | `V3_15 -> "3.15" - in - match arch with - | `I386 -> "i386/alpine", tag - | _ -> "alpine", tag - end - | `Archlinux `Latest -> - "archlinux", "latest" - | `Debian v -> begin - let tag = - match v with - | `V7 -> "7" - | `V8 -> "8" - | `V9 -> "9" - | `V10 -> "10" - | `V11 -> "11" - | `Testing -> "testing" - | `Unstable -> "unstable" - in - match arch with - | `I386 -> "i386/debian", tag - | `Aarch32 -> "arm32v7/debian", tag - | _ -> "debian", tag - end - | `Ubuntu v -> - let tag = - match v with - | `V12_04 -> "precise" - | `V14_04 -> "trusty" - | `V15_04 -> "vivid" - | `V15_10 -> "wily" - | `V16_04 -> "xenial" - | `V16_10 -> "yakkety" - | `V17_04 -> "zesty" - | `V17_10 -> "artful" - | `V18_04 -> "bionic" - | `V18_10 -> "cosmic" - | `V19_04 -> "disco" - | `V19_10 -> "eoan" - | `V20_04 -> "focal" - | `V20_10 -> "groovy" - | `V21_04 -> "hirsute" - | `V21_10 -> "impish" - | `V22_04 -> "jammy" - in - "ubuntu", tag - | `CentOS v -> - let tag = match v with `V6 -> "6" | `V7 -> "7" | `V8 -> "8" in - "centos", tag - | `Fedora v -> - let tag = - match v with - | `V21 -> "21" - | `V22 -> "22" - | `V23 -> "23" - | `V24 -> "24" - | `V25 -> "25" - | `V26 -> "26" - | `V27 -> "27" - | `V28 -> "28" - | `V29 -> "29" - | `V30 -> "30" - | `V31 -> "31" - | `V32 -> "32" - | `V33 -> "33" - | `V34 -> "34" - | `V35 -> "35" - in - "fedora", tag - | `OracleLinux v -> - let tag = - match v with - | `V7 -> "7" - | `V8 -> "8" in - "oraclelinux", tag - | `OpenSUSE v -> - let tag = - match v with - | `V42_1 -> "42.1" - | `V42_2 -> "42.2" - | `V42_3 -> "42.3" - | `V15_0 -> "15.0" - | `V15_1 -> "15.1" - | `V15_2 -> "15.2" - | `V15_3 -> "15.3" - in - "opensuse/leap", tag - | `Cygwin v -> win10_base_tag ?win10_revision `ServerCore (v : win10_release :> [> win10_release]) - | `Windows (_, v) -> win10_base_tag ?win10_revision `Windows (v : win10_release :> [> win10_release]) - -let compare a b = - String.compare (human_readable_string_of_distro a) (human_readable_string_of_distro b) diff --git a/src-opam/dockerfile_linux.ml b/src-opam/dockerfile_linux.ml deleted file mode 100644 index 73ee3cde..00000000 --- a/src-opam/dockerfile_linux.ml +++ /dev/null @@ -1,211 +0,0 @@ -(* - * Copyright (c) 2014 Anil Madhavapeddy - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - *) - -open Dockerfile -open Printf - -let run_sh fmt = ksprintf (run "sh -c %S") fmt -let run_as_user user fmt = ksprintf (run "sudo -u %s sh -c %S" user) fmt - -module Git = struct - let init ?(name="Docker") ?(email="docker@example.com") () = - run "git config --global user.email %S" email @@ - run "git config --global user.name %S" name -end - -let sudo_nopasswd = "ALL=(ALL:ALL) NOPASSWD:ALL" - -(** RPM rules *) -module RPM = struct - let update = run "yum update -y" - let install fmt = ksprintf (run "yum install -y %s && yum clean all") fmt - let groupinstall fmt = ksprintf (run "yum groupinstall -y %s && yum clean all") fmt - - let add_user ?uid ?gid ?(sudo=false) username = - let uid = match uid with Some u -> sprintf "-u %d " u | None -> "" in - let gid = match gid with Some g -> sprintf "-g %d " g | None -> "" in - let home = "/home/"^username in - (match sudo with - | false -> empty - | true -> - let sudofile = "/etc/sudoers.d/"^username in - copy_heredoc ~src:[heredoc ~strip:true "\t%s %s" username sudo_nopasswd] ~dst:sudofile () @@ - run "chmod 440 %s" sudofile @@ - run "chown root:root %s" sudofile @@ - run "sed -i.bak 's/^Defaults.*requiretty//g' /etc/sudoers") @@ - run "useradd -d %s %s%s-m -s /bin/bash %s" home uid gid username @@ - run "passwd -l %s" username @@ - run "chown -R %s:%s %s" username username home @@ - user "%s" username @@ - env ["HOME", home] @@ - workdir "%s" home @@ - run "mkdir .ssh" @@ - run "chmod 700 .ssh" - - let dev_packages ?extra () = - groupinstall "\"Development Tools\"" @@ - install "sudo passwd bzip2 patch rsync nano gcc-c++ git tar curl xz libX11-devel which m4 diffutils findutils%s" - (match extra with None -> "" | Some x -> " " ^ x) - - let install_system_ocaml = - install "ocaml ocaml-camlp4-devel ocaml-ocamldoc" -end - -(** Debian rules *) -module Apt = struct - let update = run "apt-get -y update" @@ run "DEBIAN_FRONTEND=noninteractive apt-get -y upgrade" - let install fmt = ksprintf (fun s -> update @@ run "DEBIAN_FRONTEND=noninteractive apt-get -y install %s" s) fmt - - let dev_packages ?extra () = - update @@ - copy_heredoc ~src:[heredoc ~strip:true "\tAcquire::Retries \"5\";"] ~dst:"/etc/apt/apt.conf.d/mirror-retry" () @@ - install "build-essential curl git rsync sudo unzip nano libcap-dev libx11-dev%s" - (match extra with None -> "" | Some x -> " " ^ x) - - let add_user ?uid ?gid ?(sudo=false) username = - let uid = match uid with Some u -> sprintf "--uid %d " u | None -> "" in - let gid = match gid with Some g -> sprintf "--gid %d " g | None -> "" in - let home = "/home/"^username in - (match sudo with - | false -> empty - | true -> - let sudofile = "/etc/sudoers.d/"^username in - copy_heredoc ~src:[heredoc ~strip:true "\t%s %s" username sudo_nopasswd] ~dst:sudofile () @@ - run "chmod 440 %s" sudofile @@ - run "chown root:root %s" sudofile) @@ - run "adduser %s%s--disabled-password --gecos '' %s" uid gid username @@ - run "passwd -l %s" username @@ - run "chown -R %s:%s %s" username username home @@ - user "%s" username @@ - env ["HOME", home] @@ - workdir "%s" home @@ - run "mkdir .ssh" @@ - run "chmod 700 .ssh" - - let install_system_ocaml = - install "ocaml ocaml-native-compilers camlp4-extra rsync" - -end - -(** Alpine rules *) -module Apk = struct - let update = run "apk update && apk upgrade" - let install fmt = ksprintf (fun s -> update @@ run "apk add %s" s) fmt - - let dev_packages ?extra () = - install "build-base patch tar ca-certificates git rsync curl sudo bash libx11-dev nano coreutils xz libexecinfo-dev ncurses-dev%s" - (match extra with None -> "" | Some x -> " " ^ x) - - let add_user ?uid ?gid ?(sudo=false) username = - let home = "/home/"^username in - (match gid with - | None -> empty - | Some gid -> run "addgroup -S -g %d %s" gid username) @@ - run "adduser -S %s%s%s" - (match uid with None -> "" | Some d -> sprintf "-u %d " d) - (match gid with None -> "" | Some _ -> sprintf "-G %s " username) - username @@ - (match sudo with - | false -> empty - | true -> - let sudofile = "/etc/sudoers.d/"^username in - copy_heredoc ~src:[heredoc ~strip:true "\t%s %s" username sudo_nopasswd] ~dst:sudofile () @@ - run "chmod 440 %s" sudofile @@ - run "chown root:root %s" sudofile @@ - run "sed -i.bak 's/^Defaults.*requiretty//g' /etc/sudoers") @@ - user "%s" username @@ - workdir "%s" home @@ - run "mkdir .ssh" @@ - run "chmod 700 .ssh" - - let install_system_ocaml = - run "apk add ocaml camlp4" - - let add_repository ?tag url = - run "<<-EOF cat >> /etc/apk/repositories\n\t%s\nEOF" - (match tag with None -> url | Some tag -> sprintf "@%s %s" tag url) - - let add_repositories repos = - let repos = - String.concat "" - (List.map (function None, url -> url | Some tag, url -> sprintf "\n\t@%s %s" tag url) repos) in - run "<<-EOF cat >> /etc/apk/repositories%s\nEOF" repos - -end - -(* Zypper (opensuse) rules *) -module Zypper = struct - let update = run "zypper update -y" - let install fmt = ksprintf (fun s -> update @@ run "zypper install --force-resolution -y %s" s) fmt - - let dev_packages ?extra () = - install "-t pattern devel_C_C++" @@ - install "sudo git unzip curl gcc-c++ libcap-devel xz libX11-devel bzip2 which rsync" @@ - (maybe (install "%s") extra) - - let add_user ?uid ?gid ?(sudo=false) username = - let home = "/home/"^username in - run "useradd %s%s -d %s -m --user-group %s" - (match uid with None -> "" | Some d -> sprintf "-u %d " d) - (match gid with None -> "" | Some g -> sprintf "-g %d " g) - home username @@ - (match sudo with - | false -> empty - | true -> - let sudofile = "/etc/sudoers.d/"^username in - copy_heredoc ~src:[heredoc ~strip:true "\t%s %s" username sudo_nopasswd] ~dst:sudofile () @@ - run "chmod 440 %s" sudofile @@ - run "chown root:root %s" sudofile) @@ - user "%s" username @@ - workdir "%s" home @@ - run "mkdir .ssh" @@ - run "chmod 700 .ssh" - - let install_system_ocaml = - install "ocaml camlp4 ocaml-ocamldoc" -end - -(** Pacman rules *) -module Pacman = struct - let update = run "pacman -Syu --noconfirm" - let install fmt = ksprintf (fun s -> run "pacman -Syu --noconfirm %s" s) fmt - - let dev_packages ?extra () = - install "make gcc patch tar ca-certificates git rsync curl sudo bash libx11 nano coreutils xz ncurses diffutils unzip%s" - (match extra with None -> "" | Some x -> " " ^ x) - - let add_user ?uid ?gid ?(sudo=false) username = - let home = "/home/"^username in - run "useradd %s%s -d %s -m --user-group %s" - (match uid with None -> "" | Some d -> sprintf "-u %d " d) - (match gid with None -> "" | Some g -> sprintf "-g %d " g) - home username @@ - (match sudo with - | false -> empty - | true -> - let sudofile = "/etc/sudoers.d/"^username in - copy_heredoc ~src:[heredoc ~strip:true "\t%s %s" username sudo_nopasswd] ~dst:sudofile () @@ - run "chmod 440 %s" sudofile @@ - run "chown root:root %s" sudofile) @@ - user "%s" username @@ - workdir "%s" home @@ - run "mkdir .ssh" @@ - run "chmod 700 .ssh" - - let install_system_ocaml = - run "pacman add ocaml ocaml-compiler-libs" -end diff --git a/src-opam/dockerfile_opam.ml b/src-opam/dockerfile_opam.ml index 5c4cf86a..a3068ebe 100644 --- a/src-opam/dockerfile_opam.ml +++ b/src-opam/dockerfile_opam.ml @@ -18,9 +18,10 @@ (** OPAM-specific Dockerfile rules *) open Dockerfile -module Linux = Dockerfile_linux -module Windows = Dockerfile_windows -module D = Dockerfile_distro +module Distro = Distro +module Linux = Linux +module Windows = Windows +module D = Distro module OV = Ocaml_version let personality ?arch distro = @@ -36,108 +37,131 @@ let maybe_link_opam add_default_link prefix branch = else empty (* Build opam in a separate worktree from an already cloned opam *) -let install_opam_from_source ?(add_default_link=true) ?(prefix= "/usr/local") ?(enable_0install_solver=false) ~branch ~hash () = +let install_opam_from_source ?(add_default_link = true) ?(prefix = "/usr/local") + ?(enable_0install_solver = false) ~branch ~hash () = run - "cd /tmp/opam-sources && cp -P -R -p . ../opam-build-%s && \ - cd ../opam-build-%s && git checkout %s && \ - ln -s ../opam/src_ext/archives src_ext/archives && \ - env PATH=\"/tmp/opam/bootstrap/ocaml/bin:$PATH\" ./configure --enable-cold-check%s && \ - env PATH=\"/tmp/opam/bootstrap/ocaml/bin:$PATH\" make lib-ext all && \ - mkdir -p %s/bin && cp /tmp/opam-build-%s/opam %s/bin/opam-%s && chmod a+x %s/bin/opam-%s && \ - rm -rf /tmp/opam-build-%s" - branch branch hash (if enable_0install_solver then " --with-0install-solver" else "") - prefix branch prefix branch prefix branch branch @@ - maybe_link_opam add_default_link prefix branch + "cd /tmp/opam-sources && cp -P -R -p . ../opam-build-%s && cd \ + ../opam-build-%s && git checkout %s && ln -s ../opam/src_ext/archives \ + src_ext/archives && env PATH=\"/tmp/opam/bootstrap/ocaml/bin:$PATH\" \ + ./configure --enable-cold-check%s && env \ + PATH=\"/tmp/opam/bootstrap/ocaml/bin:$PATH\" make lib-ext all && mkdir -p \ + %s/bin && cp /tmp/opam-build-%s/opam %s/bin/opam-%s && chmod a+x \ + %s/bin/opam-%s && rm -rf /tmp/opam-build-%s" + branch branch hash + (if enable_0install_solver then " --with-0install-solver" else "") + prefix branch prefix branch prefix branch branch + @@ maybe_link_opam add_default_link prefix branch let bubblewrap_minimum = (0, 4, 1) -let maybe_build_bubblewrap_from_source ?(prefix="/usr/local") distro = +let maybe_build_bubblewrap_from_source ?(prefix = "/usr/local") distro = let major, minor, revision = bubblewrap_minimum in match D.bubblewrap_version distro with | Some release when release >= bubblewrap_minimum -> empty | _ -> - let rel = Printf.sprintf "%d.%d.%d" major minor revision in - let file = Printf.sprintf "bubblewrap-%s.tar.xz" rel in - let url = Printf.sprintf "https://github.com/projectatomic/bubblewrap/releases/download/v%s/bubblewrap-%s.tar.xz" rel rel in - run "curl -fOL %s" url @@ - run "tar xf %s" file @@ - run "cd bubblewrap-%s && ./configure --prefix=%s && make && sudo make install" rel prefix @@ - run "rm -rf %s bubblewrap-%s" file rel + let rel = Printf.sprintf "%d.%d.%d" major minor revision in + let file = Printf.sprintf "bubblewrap-%s.tar.xz" rel in + let url = + Printf.sprintf + "https://github.com/projectatomic/bubblewrap/releases/download/v%s/bubblewrap-%s.tar.xz" + rel rel + in + run "curl -fOL %s" url @@ run "tar xf %s" file + @@ run + "cd bubblewrap-%s && ./configure --prefix=%s && make && sudo make \ + install" + rel prefix + @@ run "rm -rf %s bubblewrap-%s" file rel let bubblewrap_and_dev_packages distro = - let dev_packages = match D.package_manager distro with - | `Apk -> Linux.Apk.dev_packages - | `Apt -> Linux.Apt.dev_packages - | `Yum -> Linux.RPM.dev_packages - | `Zypper -> Linux.Zypper.dev_packages - | `Pacman -> Linux.Pacman.dev_packages - | `Cygwin | `Windows -> assert false + let dev_packages = + match D.package_manager distro with + | `Apk -> Linux.Apk.dev_packages + | `Apt -> Linux.Apt.dev_packages + | `Yum -> Linux.RPM.dev_packages + | `Zypper -> Linux.Zypper.dev_packages + | `Pacman -> Linux.Pacman.dev_packages + | `Cygwin | `Windows -> assert false in match D.bubblewrap_version distro with | Some version when version >= bubblewrap_minimum -> - dev_packages ~extra:"bubblewrap" () + dev_packages ~extra:"bubblewrap" () | _ -> - copy ~from:"0" ~src:["/usr/local/bin/bwrap"] ~dst:"/usr/bin/bwrap" () - @@ dev_packages () + copy ~from:"0" ~src:[ "/usr/local/bin/bwrap" ] ~dst:"/usr/bin/bwrap" () + @@ dev_packages () let install_bubblewrap_wrappers = let strip = true in - let opamrc_sandbox = heredoc ~strip -{| wrap-build-commands: ["%%{hooks}%%/sandbox.sh" "build"] + let opamrc_sandbox = + heredoc ~strip + {| wrap-build-commands: ["%%{hooks}%%/sandbox.sh" "build"] wrap-install-commands: ["%%{hooks}%%/sandbox.sh" "install"] - wrap-remove-commands: ["%%{hooks}%%/sandbox.sh" "remove"]|} in - let opamrc_nosandbox = heredoc ~strip -{| wrap-build-commands: [] + wrap-remove-commands: ["%%{hooks}%%/sandbox.sh" "remove"]|} + in + let opamrc_nosandbox = + heredoc ~strip + {| wrap-build-commands: [] wrap-install-commands: [] wrap-remove-commands: [] - required-tools: []|} in - let sandbox_enable = heredoc ~strip -{| #!/bin/sh + required-tools: []|} + in + let sandbox_enable = + heredoc ~strip + {| #!/bin/sh cp ~/.opamrc-sandbox ~/.opamrc - echo --- opam sandboxing enabled|} in - let sandbox_disable = heredoc ~strip -{| #!/bin/sh + echo --- opam sandboxing enabled|} + in + let sandbox_disable = + heredoc ~strip + {| #!/bin/sh cp ~/.opamrc-nosandbox ~/.opamrc - echo --- opam sandboxing disabled|} in + echo --- opam sandboxing disabled|} + in (* Disable bubblewrap *) - copy_heredoc ~chown:"opam" ~src:[opamrc_nosandbox] ~dst:"/home/opam/.opamrc-nosandbox" () @@ - copy_heredoc ~chown:"opam" ~src:[sandbox_disable] ~dst:"/home/opam/opam-sandbox-disable" () @@ - run "chmod a+x /home/opam/opam-sandbox-disable" @@ - run "sudo mv /home/opam/opam-sandbox-disable /usr/bin/opam-sandbox-disable" @@ + copy_heredoc ~chown:"opam" ~src:[ opamrc_nosandbox ] + ~dst:"/home/opam/.opamrc-nosandbox" () + @@ copy_heredoc ~chown:"opam" ~src:[ sandbox_disable ] + ~dst:"/home/opam/opam-sandbox-disable" () + @@ run "chmod a+x /home/opam/opam-sandbox-disable" + @@ run "sudo mv /home/opam/opam-sandbox-disable /usr/bin/opam-sandbox-disable" (* Enable bubblewrap *) - copy_heredoc ~chown:"opam" ~src:[opamrc_sandbox] ~dst:"/home/opam/.opamrc-sandbox" () @@ - copy_heredoc ~chown:"opam" ~src:[sandbox_enable] ~dst:"/home/opam/opam-sandbox-enable" () @@ - run "chmod a+x /home/opam/opam-sandbox-enable" @@ - run "sudo mv /home/opam/opam-sandbox-enable /usr/bin/opam-sandbox-enable" + @@ copy_heredoc ~chown:"opam" ~src:[ opamrc_sandbox ] + ~dst:"/home/opam/.opamrc-sandbox" () + @@ copy_heredoc ~chown:"opam" ~src:[ sandbox_enable ] + ~dst:"/home/opam/opam-sandbox-enable" () + @@ run "chmod a+x /home/opam/opam-sandbox-enable" + @@ run "sudo mv /home/opam/opam-sandbox-enable /usr/bin/opam-sandbox-enable" let header ?win10_revision ?arch ?maintainer ?img ?tag d = let platform = match arch with | Some `I386 -> Some "386" | Some `Aarch32 -> Some "arm" - | _ -> None in + | _ -> None + in let shell = match personality ?arch d with - | Some pers -> shell [pers; "/bin/bash"; "-c"] - | None -> empty in + | Some pers -> shell [ pers; "/bin/bash"; "-c" ] + | None -> empty + in let maintainer = match maintainer with | Some t -> Dockerfile.maintainer "%s" t - | None -> empty in + | None -> empty + in let parser_directives = match D.os_family_of_distro d with | `Windows | `Cygwin -> parser_directive (`Escape '`') - | _ -> parser_directive (`Syntax "docker/dockerfile:1") in + | _ -> parser_directive (`Syntax "docker/dockerfile:1") + in let img, tag = let dimg, dtag = D.base_distro_tag ?win10_revision ?arch d in let value default = function None -> default | Some str -> str in - value dimg img, value dtag tag + (value dimg img, value dtag tag) in - parser_directives @@ - comment "Autogenerated by OCaml-Dockerfile scripts" @@ - from ?platform ~tag img - @@ maintainer - @@ shell + parser_directives + @@ comment "Autogenerated by OCaml-Dockerfile scripts" + @@ from ?platform ~tag img @@ maintainer @@ shell type opam_hashes = { opam_2_0_hash : string; @@ -154,82 +178,92 @@ type opam_branch = { } let create_opam_branches opam_hashes = - let { - opam_2_0_hash; - opam_2_1_hash; - opam_master_hash; - } = opam_hashes in - opam_master_hash, - [ - { - branch = "2.0"; - hash = opam_2_0_hash; - enable_0install_solver = false; - public_name = "opam-2.0"; - aliases = ["opam"]; (* Default *) - }; - { - branch = "2.1"; - hash = opam_2_1_hash; - enable_0install_solver = true; - public_name = "opam-2.1"; - aliases = []; - }; - { - branch = "master"; - hash = opam_master_hash; - enable_0install_solver = true; - public_name = "opam-dev"; - aliases = ["opam-2.2"]; (* TODO: Remove/update when opam 2.2 is branched *) - }; - ] + let { opam_2_0_hash; opam_2_1_hash; opam_master_hash } = opam_hashes in + ( opam_master_hash, + [ + { + branch = "2.0"; + hash = opam_2_0_hash; + enable_0install_solver = false; + public_name = "opam-2.0"; + aliases = [ "opam" ]; + (* Default *) + }; + { + branch = "2.1"; + hash = opam_2_1_hash; + enable_0install_solver = true; + public_name = "opam-2.1"; + aliases = []; + }; + { + branch = "master"; + hash = opam_master_hash; + enable_0install_solver = true; + public_name = "opam-dev"; + aliases = [ "opam-2.2" ]; + (* TODO: Remove/update when opam 2.2 is branched *) + }; + ] ) let install_opams ?prefix opam_master_hash opam_branches = - run "git clone https://github.com/ocaml/opam /tmp/opam && \ - cd /tmp/opam && cp -P -R -p . ../opam-sources && \ - git checkout %s && \ - env MAKE='make -j' shell/bootstrap-ocaml.sh && \ - make -C src_ext cache-archives" opam_master_hash @@ - List.fold_left (fun acc {branch; hash; enable_0install_solver; _} -> - let add_default_link = Some false in - let enable_0install_solver = Some enable_0install_solver in - acc @@ install_opam_from_source ?add_default_link ?prefix ?enable_0install_solver ~branch ~hash () - ) empty opam_branches + run + "git clone https://github.com/ocaml/opam /tmp/opam && cd /tmp/opam && cp \ + -P -R -p . ../opam-sources && git checkout %s && env MAKE='make -j' \ + shell/bootstrap-ocaml.sh && make -C src_ext cache-archives" + opam_master_hash + @@ List.fold_left + (fun acc { branch; hash; enable_0install_solver; _ } -> + let add_default_link = Some false in + let enable_0install_solver = Some enable_0install_solver in + acc + @@ install_opam_from_source ?add_default_link ?prefix + ?enable_0install_solver ~branch ~hash ()) + empty opam_branches let copy_opams ~src ~dst opam_branches = - List.fold_left (fun acc {branch; public_name; aliases; _} -> - acc @@ - copy ~from:"0" ~src:[src^"/opam-"^branch] ~dst:(dst^"/"^public_name) () @@@ - List.map (fun alias -> run "ln %s/%s %s/%s" dst public_name dst alias) aliases - ) empty opam_branches + List.fold_left + (fun acc { branch; public_name; aliases; _ } -> + acc + @@ copy ~from:"0" + ~src:[ src ^ "/opam-" ^ branch ] + ~dst:(dst ^ "/" ^ public_name) + () + @@@ List.map + (fun alias -> run "ln %s/%s %s/%s" dst public_name dst alias) + aliases) + empty opam_branches (* Apk based Dockerfile *) -let apk_opam2 ?(labels=[]) ?arch ~opam_hashes distro () = +let apk_opam2 ?(labels = []) ?arch ~opam_hashes distro () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in - header ?arch distro @@ label (("distro_style", "apk") :: labels) + header ?arch distro + @@ label (("distro_style", "apk") :: labels) @@ Linux.Apk.install "build-base bzip2 git tar curl ca-certificates openssl" @@ Linux.Git.init () @@ maybe_build_bubblewrap_from_source distro @@ install_opams opam_master_hash opam_branches @@ run "strip /usr/local/bin/opam*" @@ from ~tag img - @@ Linux.Apk.add_repositories [ - Some "edge", "https://dl-cdn.alpinelinux.org/alpine/edge/main"; - Some "edgecommunity", "https://dl-cdn.alpinelinux.org/alpine/edge/community"; - Some "testing", "https://dl-cdn.alpinelinux.org/alpine/edge/testing"; + @@ Linux.Apk.add_repositories + [ + (Some "edge", "https://dl-cdn.alpinelinux.org/alpine/edge/main"); + ( Some "edgecommunity", + "https://dl-cdn.alpinelinux.org/alpine/edge/community" ); + (Some "testing", "https://dl-cdn.alpinelinux.org/alpine/edge/testing"); ] @@ bubblewrap_and_dev_packages distro @@ copy_opams ~src:"/usr/local/bin" ~dst:"/usr/bin" opam_branches @@ Linux.Apk.add_user ~uid:1000 ~gid:1000 ~sudo:true "opam" @@ install_bubblewrap_wrappers @@ Linux.Git.init () - (* Debian based Dockerfile *) -let apt_opam2 ?(labels=[]) ?arch distro ~opam_hashes () = +let apt_opam2 ?(labels = []) ?arch distro ~opam_hashes () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in - header ?arch distro @@ label (("distro_style", "apt") :: labels) + header ?arch distro + @@ label (("distro_style", "apt") :: labels) @@ Linux.Apt.install "build-essential curl git libcap-dev sudo" @@ Linux.Git.init () @@ maybe_build_bubblewrap_from_source distro @@ -238,11 +272,12 @@ let apt_opam2 ?(labels=[]) ?arch distro ~opam_hashes () = @@ run "ln -fs /usr/share/zoneinfo/Europe/London /etc/localtime" @@ bubblewrap_and_dev_packages distro @@ copy_opams ~src:"/usr/local/bin" ~dst:"/usr/bin" opam_branches - @@ run "echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections" + @@ run + "echo 'debconf debconf/frontend select Noninteractive' | \ + debconf-set-selections" @@ Linux.Apt.add_user ~uid:1000 ~sudo:true "opam" @@ install_bubblewrap_wrappers @@ Linux.Git.init () - (* RPM based Dockerfile. [yum_workaround] activates the overlay/yum workaround needed @@ -250,40 +285,43 @@ let apt_opam2 ?(labels=[]) ?arch distro ~opam_hashes () = [enable_powertools] enables the PowerTools repository on CentOS 8 and above. This is needed to get most of *-devel packages frequently used by opam packages. *) -let yum_opam2 ?(labels= []) ?arch ~yum_workaround ~enable_powertools ~opam_hashes distro () = +let yum_opam2 ?(labels = []) ?arch ~yum_workaround ~enable_powertools + ~opam_hashes distro () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in let workaround = if yum_workaround then - run "touch /var/lib/rpm/*" - @@ Linux.RPM.install "yum-plugin-ovl" + run "touch /var/lib/rpm/*" @@ Linux.RPM.install "yum-plugin-ovl" else empty in - header ?arch distro @@ label (("distro_style", "rpm") :: labels) + header ?arch distro + @@ label (("distro_style", "rpm") :: labels) @@ run "yum --version || dnf install -y yum" - @@ workaround - @@ Linux.RPM.update + @@ workaround @@ Linux.RPM.update @@ Linux.RPM.dev_packages ~extra:"which tar curl xz libcap-devel openssl" () @@ Linux.Git.init () @@ maybe_build_bubblewrap_from_source distro @@ install_opams ~prefix:"/usr" opam_master_hash opam_branches @@ from ~tag img @@ run "yum --version || dnf install -y yum" - @@ workaround - @@ Linux.RPM.update + @@ workaround @@ Linux.RPM.update @@ bubblewrap_and_dev_packages distro @@ copy_opams ~src:"/usr/bin" ~dst:"/usr/bin" opam_branches - @@ (if enable_powertools then run "yum config-manager --set-enabled powertools" @@ Linux.RPM.update else empty) + @@ (if enable_powertools then + run "yum config-manager --set-enabled powertools" @@ Linux.RPM.update + else empty) @@ run - "sed -i.bak '/LC_TIME LC_ALL LANGUAGE/aDefaults env_keep += \"OPAMYES OPAMJOBS OPAMVERBOSE\"' /etc/sudoers" + "sed -i.bak '/LC_TIME LC_ALL LANGUAGE/aDefaults env_keep += \ + \"OPAMYES OPAMJOBS OPAMVERBOSE\"' /etc/sudoers" @@ Linux.RPM.add_user ~uid:1000 ~sudo:true "opam" @@ install_bubblewrap_wrappers @@ Linux.Git.init () (* Zypper based Dockerfile *) -let zypper_opam2 ?(labels=[]) ?arch ~opam_hashes distro () = +let zypper_opam2 ?(labels = []) ?arch ~opam_hashes distro () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in - header ?arch distro @@ label (("distro_style", "zypper") :: labels) + header ?arch distro + @@ label (("distro_style", "zypper") :: labels) @@ Linux.Zypper.dev_packages () @@ Linux.Git.init () @@ maybe_build_bubblewrap_from_source distro @@ -295,10 +333,11 @@ let zypper_opam2 ?(labels=[]) ?arch ~opam_hashes distro () = @@ install_bubblewrap_wrappers @@ Linux.Git.init () (* Pacman based Dockerfile *) -let pacman_opam2 ?(labels=[]) ?arch ~opam_hashes distro () = +let pacman_opam2 ?(labels = []) ?arch ~opam_hashes distro () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in - header ?arch distro @@ label (("distro_style", "pacman") :: labels) + header ?arch distro + @@ label (("distro_style", "pacman") :: labels) @@ Linux.Pacman.dev_packages () @@ Linux.Git.init () @@ maybe_build_bubblewrap_from_source distro @@ -311,11 +350,15 @@ let pacman_opam2 ?(labels=[]) ?arch ~opam_hashes distro () = @@ install_bubblewrap_wrappers @@ Linux.Git.init () (* Cygwin based Dockerfile *) -let cygwin_opam2 ?win10_revision ?(labels=[]) ?arch ~opam_hashes distro () = +let cygwin_opam2 ?win10_revision ?(labels = []) ?arch ~opam_hashes distro () = let opam_master_hash, opam_branches = create_opam_branches opam_hashes in let img, tag = D.base_distro_tag ?arch distro in - let cyg = Windows.Cygwin.{ default with args = "--allow-test-packages" :: default.args } in - header ?win10_revision ?arch distro @@ label (("distro_style", "cygwin") :: labels) + let cyg = + Windows.Cygwin. + { default with args = "--allow-test-packages" :: default.args } + in + header ?win10_revision ?arch distro + @@ label (("distro_style", "cygwin") :: labels) @@ user "ContainerAdministrator" @@ Windows.Cygwin.(setup ~cyg ~extra:(cygwin_packages ()) ()) @@ Windows.Cygwin.Git.init () @@ -330,166 +373,222 @@ let cygwin_opam2 ?win10_revision ?(labels=[]) ?arch ~opam_hashes distro () = add an option to enable 0install-solver, and pass ~hash_opam_2_0 ~hash_opam_2_1 like the cygwin one *) (* Native Windows, WinGet, Cygwin based Dockerfiles *) -let windows_opam2 ?win10_revision ?winget ?(labels=[]) ?arch distro () = +let windows_opam2 ?win10_revision ?winget ?(labels = []) ?arch distro () = let version = match distro with `Windows (_, v) -> v | _ -> assert false in (match winget with - | None when Windows.Winget.is_supported version -> Windows.Winget.install_from_release ?win10_revision ~version () + | None when Windows.Winget.is_supported version -> + Windows.Winget.install_from_release ?win10_revision ~version () | _ -> empty) - @@ header ?win10_revision ?arch distro @@ label (("distro_style", "windows") :: labels) + @@ header ?win10_revision ?arch distro + @@ label (("distro_style", "windows") :: labels) @@ user "ContainerAdministrator" - @@ begin - let extra, t = match distro with - | `Windows (`Mingw, _) -> - Windows.Cygwin.mingw_packages (), empty + @@ (let extra, t = + match distro with + | `Windows (`Mingw, _) -> (Windows.Cygwin.mingw_packages (), empty) | `Windows (`Msvc, _) -> - Windows.Cygwin.msvc_packages (), - Windows.install_visual_studio_build_tools [ - "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"; - "Microsoft.VisualStudio.Component.Windows10SDK.18362"] + ( Windows.Cygwin.msvc_packages (), + Windows.install_visual_studio_build_tools + [ + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"; + "Microsoft.VisualStudio.Component.Windows10SDK.18362"; + ] ) | _ -> invalid_arg "Invalid distribution" in let extra, t' = Windows.Cygwin.ocaml_for_windows_packages ~extra () in - Windows.install_vc_redist () @@ t + Windows.install_vc_redist () + @@ t @@ Windows.sanitize_reg_path () - @@ Windows.Cygwin.setup ~extra () @@ t' - end - @@ begin if Windows.Winget.is_supported version then + @@ Windows.Cygwin.setup ~extra () + @@ t') + @@ (if Windows.Winget.is_supported version then Windows.Winget.setup ?from:winget () @@ Windows.Winget.dev_packages ~version () - else empty end - @@ Windows.Cygwin.Git.init () - @@ Windows.cleanup () - -let gen_opam2_distro ?win10_revision ?winget ?(clone_opam_repo=true) ?arch ?labels ~opam_hashes d = - let fn = match D.package_manager d with - | `Apk -> apk_opam2 ?labels ?arch ~opam_hashes d () - | `Apt -> apt_opam2 ?labels ?arch ~opam_hashes d () - | `Yum -> - let yum_workaround = match d with `CentOS `V7 -> true | _ -> false in - let enable_powertools = match d with `CentOS (`V6 | `V7) -> false | `CentOS _ -> true | _ -> false in - yum_opam2 ?labels ?arch ~yum_workaround ~enable_powertools ~opam_hashes d () - | `Zypper -> zypper_opam2 ?labels ?arch ~opam_hashes d () - | `Pacman -> pacman_opam2 ?labels ?arch ~opam_hashes d () - | `Cygwin -> cygwin_opam2 ?win10_revision ?labels ?arch ~opam_hashes d () - | `Windows -> windows_opam2 ?win10_revision ?winget ?labels ?arch d () + else empty) + @@ Windows.Cygwin.Git.init () @@ Windows.cleanup () + +let gen_opam2_distro ?win10_revision ?winget ?(clone_opam_repo = true) ?arch + ?labels ~opam_hashes d = + let fn = + match D.package_manager d with + | `Apk -> apk_opam2 ?labels ?arch ~opam_hashes d () + | `Apt -> apt_opam2 ?labels ?arch ~opam_hashes d () + | `Yum -> + let yum_workaround = match d with `CentOS `V7 -> true | _ -> false in + let enable_powertools = + match d with + | `CentOS (`V6 | `V7) -> false + | `CentOS _ -> true + | _ -> false + in + yum_opam2 ?labels ?arch ~yum_workaround ~enable_powertools ~opam_hashes + d () + | `Zypper -> zypper_opam2 ?labels ?arch ~opam_hashes d () + | `Pacman -> pacman_opam2 ?labels ?arch ~opam_hashes d () + | `Cygwin -> cygwin_opam2 ?win10_revision ?labels ?arch ~opam_hashes d () + | `Windows -> windows_opam2 ?win10_revision ?winget ?labels ?arch d () + in + let clone = + if clone_opam_repo then + let url = Distro.(os_family_of_distro d |> opam_repository) in + run "git clone %S /home/opam/opam-repository" url + else empty + in + let pers = + match personality ?arch d with + | None -> empty + | Some pers -> entrypoint_exec [ pers ] in - let clone = if clone_opam_repo then - let url = Dockerfile_distro.(os_family_of_distro d |> opam_repository) in - run "git clone %S /home/opam/opam-repository" url - else empty in - let pers = match personality ?arch d with - | None -> empty | Some pers -> entrypoint_exec [pers] in (D.tag_of_distro d, fn @@ clone @@ pers) let create_switch ~arch distro t = - let create_switch switch pkg = run "opam switch create %s %s" (OV.to_string switch) pkg in + let create_switch switch pkg = + run "opam switch create %s %s" (OV.to_string switch) pkg + in let switch = OV.with_patch t None in match distro with | `Windows (port, _) -> - let (pn, pv) = Dockerfile_windows.ocaml_for_windows_package_exn ~port ~arch ~switch in - create_switch switch (pv ^ pn) - | _ -> - create_switch switch (Ocaml_version.Opam.V2.name switch) + let pn, pv = Windows.ocaml_for_windows_package_exn ~port ~arch ~switch in + create_switch switch (pv ^ pn) + | _ -> create_switch switch (Ocaml_version.Opam.V2.name switch) let all_ocaml_compilers hub_id arch distro = let distro_tag = D.tag_of_distro distro in - let os_family = Dockerfile_distro.os_family_of_distro distro in + let os_family = Distro.os_family_of_distro distro in let compilers = - OV.Releases.recent |> - List.filter (fun ov -> D.distro_supported_on arch ov distro) |> fun ovs -> + OV.Releases.recent + |> List.filter (fun ov -> D.distro_supported_on arch ov distro) + |> fun ovs -> let add_beta_remote = if List.exists OV.Releases.is_dev ovs then - run "opam repo add beta git+https://github.com/ocaml/ocaml-beta-repository --set-default" - else empty in + run + "opam repo add beta \ + git+https://github.com/ocaml/ocaml-beta-repository --set-default" + else empty + in add_beta_remote @@@ List.map (create_switch ~arch distro) ovs in let d = - let pers = match personality ~arch distro with - | None -> [] | Some pers -> [pers] in - let sandbox = match os_family with + let pers = + match personality ~arch distro with None -> [] | Some pers -> [ pers ] + in + let sandbox = + match os_family with | `Linux -> run "opam-sandbox-disable" | `Windows | `Cygwin -> empty in header ~arch ~tag:(Printf.sprintf "%s-opam" distro_tag) ~img:hub_id distro - @@ workdir "/home/opam/opam-repository" @@ run "git pull origin master" + @@ workdir "/home/opam/opam-repository" + @@ run "git pull origin master" @@ sandbox @@ run "opam init -k git -a /home/opam/opam-repository --bare%s" (if os_family = `Windows then " --disable-sandboxing" else "") @@ compilers - @@ run "opam switch %s" (OV.(to_string (with_patch OV.Releases.latest None))) - @@ entrypoint_exec (pers @ ["opam"; "config"; "exec"; "--"]) + @@ run "opam switch %s" OV.(to_string (with_patch OV.Releases.latest None)) + @@ entrypoint_exec (pers @ [ "opam"; "config"; "exec"; "--" ]) @@ run "opam install -y depext%s" (if os_family = `Windows then " depext-cygwinports" else "") - @@ env ["OPAMYES","1"] - @@ match os_family with - | `Linux | `Cygwin -> cmd "bash" - | `Windows -> cmd_exec ["cmd.exe"] + @@ env [ ("OPAMYES", "1") ] + @@ + match os_family with + | `Linux | `Cygwin -> cmd "bash" + | `Windows -> cmd_exec [ "cmd.exe" ] in (distro_tag, d) let tag_of_ocaml_version ov = - Ocaml_version.with_patch ov None |> - Ocaml_version.to_string |> - String.map (function '+' -> '-' | x -> x) + Ocaml_version.with_patch ov None + |> Ocaml_version.to_string + |> String.map (function '+' -> '-' | x -> x) let separate_ocaml_compilers hub_id arch distro = let distro_tag = D.tag_of_distro distro in - let os_family = Dockerfile_distro.os_family_of_distro distro in - OV.Releases.recent_with_dev |> List.filter (fun ov -> D.distro_supported_on arch ov distro) + let os_family = Distro.os_family_of_distro distro in + OV.Releases.recent_with_dev + |> List.filter (fun ov -> D.distro_supported_on arch ov distro) |> List.map (fun ov -> let add_remote = if OV.Releases.is_dev ov then - run "opam repo add beta git+https://github.com/ocaml/ocaml-beta-repository --set-default" - else empty in - let default_switch_name = OV.(with_patch (with_variant ov None) None |> to_string) in + run + "opam repo add beta \ + git+https://github.com/ocaml/ocaml-beta-repository \ + --set-default" + else empty + in + let default_switch_name = + OV.(with_patch (with_variant ov None) None |> to_string) + in let variants = - empty @@@ List.map (create_switch ~arch distro) (OV.Opam.V2.switches arch ov) + empty + @@@ List.map + (create_switch ~arch distro) + (OV.Opam.V2.switches arch ov) in let d = - let pers = match personality ~arch distro with - | None -> [] | Some pers -> [pers] in - let sandbox = match os_family with + let pers = + match personality ~arch distro with + | None -> [] + | Some pers -> [ pers ] + in + let sandbox = + match os_family with | `Linux -> run "opam-sandbox-disable" - | `Windows | `Cygwin -> empty in - header ~arch ~tag:(Printf.sprintf "%s-opam" distro_tag) ~img:hub_id distro + | `Windows | `Cygwin -> empty + in + header ~arch + ~tag:(Printf.sprintf "%s-opam" distro_tag) + ~img:hub_id distro @@ workdir "/home/opam/opam-repository" @@ sandbox @@ run "opam init -k git -a /home/opam/opam-repository --bare%s" (if os_family = `Windows then "--disable-sandboxing" else "") - @@ add_remote - @@ variants + @@ add_remote @@ variants @@ run "opam switch %s" default_switch_name @@ run "opam install -y depext%s" (if os_family = `Windows then "depext-cygwinports" else "") - @@ env ["OPAMYES","1"] - @@ entrypoint_exec (pers @ ["opam"; "config"; "exec"; "--"]) - @@ match os_family with - | `Linux | `Cygwin -> cmd "bash" - | `Windows -> cmd_exec ["cmd.exe"] + @@ env [ ("OPAMYES", "1") ] + @@ entrypoint_exec (pers @ [ "opam"; "config"; "exec"; "--" ]) + @@ + match os_family with + | `Linux | `Cygwin -> cmd "bash" + | `Windows -> cmd_exec [ "cmd.exe" ] in - (Printf.sprintf "%s-ocaml-%s" distro_tag (tag_of_ocaml_version ov), d) ) - + (Printf.sprintf "%s-ocaml-%s" distro_tag (tag_of_ocaml_version ov), d)) let deprecated = header (`Alpine `Latest) - @@ run "echo 'This container is now deprecated and no longer supported. Please see https://github.com/ocaml/infrastructure/wiki/Containers for the latest supported tags. Try to use the longer term supported aliases instead of specific distribution versions if you want to avoid seeing this message in the future.' && exit 1" + @@ run + "echo 'This container is now deprecated and no longer supported. Please \ + see https://github.com/ocaml/infrastructure/wiki/Containers for the \ + latest supported tags. Try to use the longer term supported aliases \ + instead of specific distribution versions if you want to avoid seeing \ + this message in the future.' && exit 1" let multiarch_manifest ~target ~platforms = let ms = List.map (fun (image, arch) -> Printf.sprintf - " -\n image: %s\n platform:\n architecture: %s\n os: linux" - image arch) + " -\n\ + \ image: %s\n\ + \ platform:\n\ + \ architecture: %s\n\ + \ os: linux" image arch) platforms |> String.concat "\n" in Printf.sprintf "image: %s\nmanifests:\n%s" target ms (* Clone and build opam from source (legacy function) *) -let install_opam_from_source ?(add_default_link=true) ?(prefix= "/usr/local") ?(enable_0install_solver=false) ~branch ~hash () = - run "git clone https://github.com/ocaml/opam /tmp/opam && cd /tmp/opam && git checkout %s" hash @@ - Linux.run_sh - "cd /tmp/opam && make%s cold && mkdir -p %s/bin && cp /tmp/opam/opam %s/bin/opam-%s && chmod a+x %s/bin/opam-%s && rm -rf /tmp/opam" - (if enable_0install_solver then " CONFIGURE_ARGS=--with-0install-solver" else "") prefix prefix branch prefix branch @@ - maybe_link_opam add_default_link prefix branch +let install_opam_from_source ?(add_default_link = true) ?(prefix = "/usr/local") + ?(enable_0install_solver = false) ~branch ~hash () = + run + "git clone https://github.com/ocaml/opam /tmp/opam && cd /tmp/opam && git \ + checkout %s" + hash + @@ Linux.run_sh + "cd /tmp/opam && make%s cold && mkdir -p %s/bin && cp /tmp/opam/opam \ + %s/bin/opam-%s && chmod a+x %s/bin/opam-%s && rm -rf /tmp/opam" + (if enable_0install_solver then " CONFIGURE_ARGS=--with-0install-solver" + else "") + prefix prefix branch prefix branch + @@ maybe_link_opam add_default_link prefix branch diff --git a/src-opam/dockerfile_opam.mli b/src-opam/dockerfile_opam.mli index 50903d49..e71bc68f 100644 --- a/src-opam/dockerfile_opam.mli +++ b/src-opam/dockerfile_opam.mli @@ -22,12 +22,22 @@ there change, so please contact [anil@recoil.org] if you depend on these functions for your own infrastructure. *) +module Distro = Distro +module Linux = Linux +module Windows = Windows + val run_as_opam : ('a, unit, string, Dockerfile.t) format4 -> 'a (** [run_as_opam fmt] runs the command specified by the [fmt] format string as the [opam] user. *) -val install_opam_from_source : ?add_default_link:bool -> - ?prefix:string -> ?enable_0install_solver:bool -> branch:string -> hash:string -> unit -> Dockerfile.t +val install_opam_from_source : + ?add_default_link:bool -> + ?prefix:string -> + ?enable_0install_solver:bool -> + branch:string -> + hash:string -> + unit -> + Dockerfile.t (** Commands to install OPAM via a source code checkout from GitHub. The [branch] can be a git tag or branch (e.g. [2.0] for opam 2.0.x or [2.1] for the opam 2.1.x). @@ -46,14 +56,14 @@ type opam_hashes = { } val gen_opam2_distro : - ?win10_revision:Dockerfile_distro.win10_lcu -> + ?win10_revision:Distro.win10_lcu -> ?winget:string -> ?clone_opam_repo:bool -> ?arch:Ocaml_version.arch -> ?labels:(string * string) list -> opam_hashes:opam_hashes -> - Dockerfile_distro.t - -> string * Dockerfile.t + Distro.t -> + string * Dockerfile.t (** [gen_opam2_distro ~opam_hashes d] will generate a Dockerfile for Linux distribution [d] with opam 2.0, opam 2.1, opam 2.2 and opam master, per hash given in parameter. @@ -68,14 +78,13 @@ val gen_opam2_distro : winget will be pulled from the [winget] external image. *) val all_ocaml_compilers : - string -> Ocaml_version.arch -> Dockerfile_distro.t -> string * Dockerfile.t + string -> Ocaml_version.arch -> Distro.t -> string * Dockerfile.t (** [all_ocaml_compilers hub_id arch distro] will generate an opam2 container that has all the recent OCaml compilers installed into a distribution [distro] on architecture [arch]. *) val separate_ocaml_compilers : - string -> Ocaml_version.arch -> Dockerfile_distro.t - -> (string * Dockerfile.t) list + string -> Ocaml_version.arch -> Distro.t -> (string * Dockerfile.t) list (** [separate_ocaml_compilers hub_id arch distro] will install a list of Dockerfiles that build individual OCaml compiler versions and their variants (e.g. flambda) in separate containers. *) @@ -85,6 +94,7 @@ val deprecated : Dockerfile.t is used to replace unsupported containers on the Hub rather than leaving an unmaintained distribution lying around with possible security holes. *) -val multiarch_manifest : target:string -> platforms:(string * string) list -> string +val multiarch_manifest : + target:string -> platforms:(string * string) list -> string (** [multiarch_manifest ~target ~platforms] will generate a manifest-tool compliant yaml file to build a [target] on the given multiarch [platforms]. *) diff --git a/src-opam/dockerfile_windows.ml b/src-opam/dockerfile_windows.ml deleted file mode 100644 index 1a9ea074..00000000 --- a/src-opam/dockerfile_windows.ml +++ /dev/null @@ -1,215 +0,0 @@ -(* - * Copyright (c) 2020 - 2021 Tarides - Antonin Décimo - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - *) - -open Dockerfile -open Printf - -let run_cmd fmt = ksprintf (run "cmd /S /C %s") fmt -let run_powershell ?(escape=Fun.id) fmt = ksprintf (fun s -> run {|powershell -Command "%s"|} (escape s)) fmt -let run_vc ~arch fmt = - let arch = match arch with - | `I386 -> "x86" | `X86_64 -> "amd64" - | `Aarch64 | `Aarch32 | `Ppc64le | `S390x | `Riscv64 -> invalid_arg "Unsupported architecture" - in - ksprintf (run {|cd C:\BuildTools\VC\Auxiliary\Build && vcvarsall.bat %s && %s|} arch) fmt -let run_ocaml_env args fmt = ksprintf (run {|ocaml-env exec %s -- %s|} (String.concat " " args)) fmt - -let install_vc_redist ?(vs_version="16") () = - add ~src:["https://aka.ms/vs/" ^ vs_version ^ "/release/vc_redist.x64.exe"] ~dst:{|C:\TEMP\|} () - @@ run {|C:\TEMP\vc_redist.x64.exe /install /passive /norestart /log C:\TEMP\vc_redist.log|} - -let install_visual_studio_build_tools ?(vs_version="16") components = - let install = - let fmt = format_of_string - {|C:\TEMP\Install.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ` - --installPath C:\BuildTools --channelUri C:\TEMP\VisualStudio.chman ` - --installChannelUri C:\TEMP\VisualStudio.chman%s|} in - run fmt (List.fold_left (fun acc component -> - acc ^ " `\n --add " ^ component) "" components) - in - (* https://docs.microsoft.com/en-us/visualstudio/install/advanced-build-tools-container?view=vs-2019#install-script *) - add ~src:["https://raw.githubusercontent.com/avsm/ocaml-dockerfile/master/src-opam/Install.cmd"] - ~dst:{|C:\TEMP\|} () - @@ add ~src:["https://aka.ms/vscollect.exe"] ~dst:{|C:\TEMP\collect.exe|} () - @@ add ~src:["https://aka.ms/vs/" ^ vs_version ^ "/release/channel"] ~dst:{|C:\TEMP\VisualStudio.chman|} () - @@ add ~src:["https://aka.ms/vs/" ^ vs_version ^ "/release/vs_buildtools.exe"] ~dst:{|C:\TEMP\vs_buildtools.exe|} () - @@ install - -let sanitize_reg_path () = - run {|for /f "tokens=1,2,*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path ^| findstr /r "\\$"') do ` - for /f "delims=" %%l in ('cmd /v:on /c "set v=%%c&& echo !v:~0,-1!"') do ` - reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path /t REG_EXPAND_SZ /f /d "%%l"|} - -let prepend_path paths = - let paths = String.concat ";" paths in - run {|for /f "tokens=1,2,*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path ^| findstr /r "^[^H]"') do ` - reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path /t REG_EXPAND_SZ /f /d "%s;%%c"|} paths - -let ocaml_for_windows_package_exn ~switch ~port ~arch = - let variant = - let bitness = if Ocaml_version.arch_is_32bit arch then "32" else "64" in - match arch with - | `X86_64 | `I386 -> - (match port with `Mingw -> "mingw" | `Msvc -> "msvc") ^ bitness - | _ -> invalid_arg "Unsupported architecture" - in - let _, pkgver = Ocaml_version.Opam.V2.package switch in - ("ocaml-variants", pkgver ^ "+" ^ variant) - -let cleanup () = - run_powershell {|Remove-Item 'C:\TEMP' -Recurse|} - -module Cygwin = struct - type cyg = { - root : string; - site : string; - args : string list; - } - - let cygsetup = {|C:\cygwin-setup-x86_64.exe|} - let cygcache = {|C:\TEMP\cache|} - - let default = { - root = {|C:\cygwin64|}; - site = "https://mirrors.kernel.org/sourceware/cygwin/"; - args = ["--quiet-mode"; "--no-shortcuts"; "--no-startmenu"; "--no-desktop"; - "--only-site"; "--local-package-dir"; cygcache]; - } - - let run_sh ?(cyg=default) fmt = ksprintf (run {|%s\bin\bash.exe --login -c "%s"|} cyg.root) fmt - let run_sh_ocaml_env ?(cyg=default) args fmt = ksprintf (run_sh ~cyg "ocaml-env exec %s -- %s" (String.concat " " args)) fmt - - let install_cygsympathy_from_source cyg = - run {|mkdir %s\lib\cygsympathy && mkdir %s\etc\postinstall|} cyg.root cyg.root - @@ add ~src:["https://raw.githubusercontent.com/metastack/cygsympathy/master/cygsympathy.cmd"] - ~dst:(cyg.root ^ {|\lib\cygsympathy\|}) () - @@ add ~src:["https://raw.githubusercontent.com/metastack/cygsympathy/master/cygsympathy.sh"] - ~dst:(cyg.root ^ {|\lib\cygsympathy\cygsympathy|}) () - (* Beware: CygSymPathy must be executed last, or it may miss files - installed by other post-install scripts. Use a name that is - greater than every other script in the lexicographic order. *) - @@ run {|mklink %s\etc\postinstall\zp_zcygsympathy.sh %s\lib\cygsympathy\cygsympathy|} cyg.root cyg.root - - let install_msvs_tools_from_source ?(version="0.4.1") cyg = - add ~src:["https://github.com/metastack/msvs-tools/archive/" ^ version ^ ".tar.gz"] - ~dst:({|C:\TEMP\msvs-tools.tar.gz|}) () - @@ run_sh ~cyg {|cd /tmp && tar -xf /cygdrive/c/TEMP/msvs-tools.tar.gz && cp msvs-tools-%s/msvs-detect msvs-tools-%s/msvs-promote-path /bin|} version version - - let cygwin ?(cyg=default) fmt = - ksprintf (run {|%s %s --root %s --site %s --symlink-type=wsl %s|} cygsetup (String.concat " " cyg.args) cyg.root cyg.site) fmt - - let install ?(cyg=default) fmt = - ksprintf (cygwin ~cyg "--packages %s") fmt - - let setup ?(cyg=default) ?(winsymlinks_native=true) ?(extra=[]) () = - (if winsymlinks_native then env [("CYGWIN", "winsymlinks:native")] else empty) - @@ add ~src:["https://www.cygwin.com/setup-x86_64.exe"] ~dst:{|C:\cygwin-setup-x86_64.exe|} () - @@ install_cygsympathy_from_source cyg - @@ cygwin ~cyg "--packages %s" (extra |> List.sort_uniq String.compare |> String.concat ",") - @@ install_msvs_tools_from_source cyg - @@ prepend_path (List.map ((^) cyg.root) [{|\bin|}]) - @@ run {|awk -i inplace "/(^#)|(^$)/{print;next}{$4=""noacl,""$4; print}" %s\etc\fstab|} cyg.root - @@ workdir {|%s\home\opam|} cyg.root - - let update ?(cyg=default) () = - run {|%s %s --root %s --site %s --upgrade-also|} cygsetup (String.concat " " cyg.args) cyg.root cyg.site - - let cygwin_packages ?(extra=[]) ?(flexdll_version="0.39-1") () = - (* 2021-03-19: flexdll 0.39 is required, but is in Cygwin testing *) - "make" :: "diffutils" :: "ocaml" :: "gcc-core" :: "git" :: "patch" :: "m4" - :: "cygport" :: ("flexdll="^flexdll_version) :: extra - - let mingw_packages ?(extra=[]) () = "make" :: "diffutils" :: "mingw64-x86_64-gcc-core" :: extra - let msvc_packages ?(extra=[]) () = "make" :: "diffutils" :: extra - - let ocaml_for_windows_packages ?cyg ?(extra=[]) ?(version="0.0.0.2") () = - let packages = "make" :: "diffutils" :: "mingw64-x86_64-gcc-g++" :: "vim" :: "git" - :: "curl" :: "rsync" :: "unzip" :: "patch" :: "m4" :: extra in - let t = - add ~src:["https://github.com/fdopen/opam-repository-mingw/releases/download/" ^ version ^ "/opam64.tar.xz"] - ~dst:{|C:\TEMP\|} () - @@ run_sh ?cyg {|cd /tmp && tar -xf /cygdrive/c/TEMP/opam64.tar.xz && ./opam64/install.sh --prefix=/usr && rm -rf opam64 opam64.tar.xz|} in - packages, t - - module Git = struct - let init ?(cyg=default) ?(name="Docker") ?(email="docker@example.com") () = - env ["HOME", cyg.root ^ {|\home\opam|}] - @@ run_sh ~cyg "git config --global user.email '%s' && \ - git config --global user.name '%s' && \ - git config --system core.longpaths true && \ - git config --global --add safe.directory /home/opam/opam-repository" email name - end -end - -module Winget = struct - let is_supported version = - not (List.mem version [`V1507; `Ltsc2015; `V1511; `V1607; `Ltsc2016; `V1703; `V1709; `V1803]) - - let winget = "winget-builder" - - let header ?win10_revision ?(version=(Dockerfile_distro.win10_latest_image : Dockerfile_distro.win10_release :> Dockerfile_distro.win_all)) () = - let img, tag = Dockerfile_distro.win10_base_tag ?win10_revision `Windows version in - parser_directive (`Escape '`') - @@ from ~alias:winget ~tag img - @@ user "ContainerAdministrator" - - let footer path = - run {|mkdir "C:\Program Files\winget-cli"|} - @@ run {|move "C:\TEMP\winget-cli\%s\winget.exe" "C:\Program Files\winget-cli\"|} path - @@ run {|move "C:\TEMP\winget-cli\%s\WindowsPackageManager.dll" "C:\Program Files\winget-cli\"|} path - @@ run {|move "C:\TEMP\winget-cli\%s\resources.pri" "C:\Program Files\winget-cli\"|} path - |> crunch - - let install_from_release ?win10_revision ?version ?winget_version () = - let file = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe." in - let src = - let src = "https://github.com/microsoft/winget-cli/releases/" in - match winget_version with - | None -> src ^ "latest/download/" ^ file ^ "msixbundle" - | Some ver -> src ^ "download/" ^ ver ^ "/" ^ file ^ "msixbundle" - in - let dst = {|C:\TEMP\|} ^ file ^ "zip" in - header ?win10_revision ?version () - @@ add ~src:[src] ~dst () - @@ run_powershell {|Expand-Archive -LiteralPath %s -DestinationPath C:\TEMP\winget-cli -Force|} dst - @@ run {|ren C:\TEMP\winget-cli\AppInstaller_x64.msix AppInstaller_x64.zip|} - @@ run_powershell {|Expand-Archive -LiteralPath C:\TEMP\winget-cli\AppInstaller_x64.zip -DestinationPath C:\TEMP\winget-cli\ -Force|} - @@ footer "" - - let setup ?(from=winget) () = - let escape s = String.(concat {|""""|} (split_on_char '"' s)) in - copy ~from ~src:[{|C:\Program Files\winget-cli|}] ~dst:{|C:\Program Files\winget-cli|} () - @@ prepend_path [{|C:\Program Files\winget-cli|}] - @@ run_powershell ~escape {|$path=(Join-Path $env:LOCALAPPDATA 'Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState'); New-Item $path -ItemType Directory -Force; '{ "$schema": "https://aka.ms/winget-settings.schema.json", "telemetry": { "disable": "true" } }' | Out-File -encoding ASCII (Join-Path $path 'settings.json')|} - - let install pkgs = - List.fold_left (fun acc pkg -> acc @@ run "winget install --exact --accept-source-agreements --accept-package-agreements %s" pkg) empty pkgs - - let dev_packages ?version ?extra () = - match version with - (* 2021-04-01: Installing git fails with exit-code 2316632065. *) - | Some `V1809 -> maybe install extra - | _ -> install ["Git.Git"] @@ maybe install extra - - module Git = struct - let init ?(name="Docker") ?(email="docker@example.com") () = - run "git config --global user.email %S && \ - git config --global user.name %S && \ - git config --system core.longpaths true && \ - git config --global --add safe.directory C:/cygwin64/home/opam/opam-repository" email name - end -end diff --git a/src-opam/dune b/src-opam/dune index ee09e09f..8fe9763f 100644 --- a/src-opam/dune +++ b/src-opam/dune @@ -2,7 +2,6 @@ (name dockerfile_opam) (public_name dockerfile-opam) (synopsis "Dockerfile functions to generate opam2 base containers") - (wrapped false) (libraries ocaml-version dockerfile fmt sexplib astring) (preprocess (per_module diff --git a/src-opam/linux.ml b/src-opam/linux.ml new file mode 100644 index 00000000..1dd9e116 --- /dev/null +++ b/src-opam/linux.ml @@ -0,0 +1,234 @@ +(* + * Copyright (c) 2014 Anil Madhavapeddy + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *) + +open Dockerfile +open Printf + +let run_sh fmt = ksprintf (run "sh -c %S") fmt +let run_as_user user fmt = ksprintf (run "sudo -u %s sh -c %S" user) fmt + +module Git = struct + let init ?(name = "Docker") ?(email = "docker@example.com") () = + run "git config --global user.email %S" email + @@ run "git config --global user.name %S" name +end + +let sudo_nopasswd = "ALL=(ALL:ALL) NOPASSWD:ALL" + +(** RPM rules *) +module RPM = struct + let update = run "yum update -y" + let install fmt = ksprintf (run "yum install -y %s && yum clean all") fmt + + let groupinstall fmt = + ksprintf (run "yum groupinstall -y %s && yum clean all") fmt + + let add_user ?uid ?gid ?(sudo = false) username = + let uid = match uid with Some u -> sprintf "-u %d " u | None -> "" in + let gid = match gid with Some g -> sprintf "-g %d " g | None -> "" in + let home = "/home/" ^ username in + (match sudo with + | false -> empty + | true -> + let sudofile = "/etc/sudoers.d/" ^ username in + copy_heredoc + ~src:[ heredoc ~strip:true "\t%s %s" username sudo_nopasswd ] + ~dst:sudofile () + @@ run "chmod 440 %s" sudofile + @@ run "chown root:root %s" sudofile + @@ run "sed -i.bak 's/^Defaults.*requiretty//g' /etc/sudoers") + @@ run "useradd -d %s %s%s-m -s /bin/bash %s" home uid gid username + @@ run "passwd -l %s" username + @@ run "chown -R %s:%s %s" username username home + @@ user "%s" username + @@ env [ ("HOME", home) ] + @@ workdir "%s" home @@ run "mkdir .ssh" @@ run "chmod 700 .ssh" + + let dev_packages ?extra () = + groupinstall "\"Development Tools\"" + @@ install + "sudo passwd bzip2 patch rsync nano gcc-c++ git tar curl xz \ + libX11-devel which m4 diffutils findutils%s" + (match extra with None -> "" | Some x -> " " ^ x) + + let install_system_ocaml = install "ocaml ocaml-camlp4-devel ocaml-ocamldoc" +end + +(** Debian rules *) +module Apt = struct + let update = + run "apt-get -y update" + @@ run "DEBIAN_FRONTEND=noninteractive apt-get -y upgrade" + + let install fmt = + ksprintf + (fun s -> + update @@ run "DEBIAN_FRONTEND=noninteractive apt-get -y install %s" s) + fmt + + let dev_packages ?extra () = + update + @@ copy_heredoc + ~src:[ heredoc ~strip:true "\tAcquire::Retries \"5\";" ] + ~dst:"/etc/apt/apt.conf.d/mirror-retry" () + @@ install + "build-essential curl git rsync sudo unzip nano libcap-dev \ + libx11-dev%s" + (match extra with None -> "" | Some x -> " " ^ x) + + let add_user ?uid ?gid ?(sudo = false) username = + let uid = match uid with Some u -> sprintf "--uid %d " u | None -> "" in + let gid = match gid with Some g -> sprintf "--gid %d " g | None -> "" in + let home = "/home/" ^ username in + (match sudo with + | false -> empty + | true -> + let sudofile = "/etc/sudoers.d/" ^ username in + copy_heredoc + ~src:[ heredoc ~strip:true "\t%s %s" username sudo_nopasswd ] + ~dst:sudofile () + @@ run "chmod 440 %s" sudofile + @@ run "chown root:root %s" sudofile) + @@ run "adduser %s%s--disabled-password --gecos '' %s" uid gid username + @@ run "passwd -l %s" username + @@ run "chown -R %s:%s %s" username username home + @@ user "%s" username + @@ env [ ("HOME", home) ] + @@ workdir "%s" home @@ run "mkdir .ssh" @@ run "chmod 700 .ssh" + + let install_system_ocaml = + install "ocaml ocaml-native-compilers camlp4-extra rsync" +end + +(** Alpine rules *) +module Apk = struct + let update = run "apk update && apk upgrade" + let install fmt = ksprintf (fun s -> update @@ run "apk add %s" s) fmt + + let dev_packages ?extra () = + install + "build-base patch tar ca-certificates git rsync curl sudo bash \ + libx11-dev nano coreutils xz libexecinfo-dev ncurses-dev%s" + (match extra with None -> "" | Some x -> " " ^ x) + + let add_user ?uid ?gid ?(sudo = false) username = + let home = "/home/" ^ username in + (match gid with + | None -> empty + | Some gid -> run "addgroup -S -g %d %s" gid username) + @@ run "adduser -S %s%s%s" + (match uid with None -> "" | Some d -> sprintf "-u %d " d) + (match gid with None -> "" | Some _ -> sprintf "-G %s " username) + username + @@ (match sudo with + | false -> empty + | true -> + let sudofile = "/etc/sudoers.d/" ^ username in + copy_heredoc + ~src:[ heredoc ~strip:true "\t%s %s" username sudo_nopasswd ] + ~dst:sudofile () + @@ run "chmod 440 %s" sudofile + @@ run "chown root:root %s" sudofile + @@ run "sed -i.bak 's/^Defaults.*requiretty//g' /etc/sudoers") + @@ user "%s" username @@ workdir "%s" home @@ run "mkdir .ssh" + @@ run "chmod 700 .ssh" + + let install_system_ocaml = run "apk add ocaml camlp4" + + let add_repository ?tag url = + run "<<-EOF cat >> /etc/apk/repositories\n\t%s\nEOF" + (match tag with None -> url | Some tag -> sprintf "@%s %s" tag url) + + let add_repositories repos = + let repos = + String.concat "" + (List.map + (function + | None, url -> url | Some tag, url -> sprintf "\n\t@%s %s" tag url) + repos) + in + run "<<-EOF cat >> /etc/apk/repositories%s\nEOF" repos +end + +(* Zypper (opensuse) rules *) +module Zypper = struct + let update = run "zypper update -y" + + let install fmt = + ksprintf + (fun s -> update @@ run "zypper install --force-resolution -y %s" s) + fmt + + let dev_packages ?extra () = + install "-t pattern devel_C_C++" + @@ install + "sudo git unzip curl gcc-c++ libcap-devel xz libX11-devel bzip2 which \ + rsync" + @@ maybe (install "%s") extra + + let add_user ?uid ?gid ?(sudo = false) username = + let home = "/home/" ^ username in + run "useradd %s%s -d %s -m --user-group %s" + (match uid with None -> "" | Some d -> sprintf "-u %d " d) + (match gid with None -> "" | Some g -> sprintf "-g %d " g) + home username + @@ (match sudo with + | false -> empty + | true -> + let sudofile = "/etc/sudoers.d/" ^ username in + copy_heredoc + ~src:[ heredoc ~strip:true "\t%s %s" username sudo_nopasswd ] + ~dst:sudofile () + @@ run "chmod 440 %s" sudofile + @@ run "chown root:root %s" sudofile) + @@ user "%s" username @@ workdir "%s" home @@ run "mkdir .ssh" + @@ run "chmod 700 .ssh" + + let install_system_ocaml = install "ocaml camlp4 ocaml-ocamldoc" +end + +(** Pacman rules *) +module Pacman = struct + let update = run "pacman -Syu --noconfirm" + let install fmt = ksprintf (fun s -> run "pacman -Syu --noconfirm %s" s) fmt + + let dev_packages ?extra () = + install + "make gcc patch tar ca-certificates git rsync curl sudo bash libx11 nano \ + coreutils xz ncurses diffutils unzip%s" + (match extra with None -> "" | Some x -> " " ^ x) + + let add_user ?uid ?gid ?(sudo = false) username = + let home = "/home/" ^ username in + run "useradd %s%s -d %s -m --user-group %s" + (match uid with None -> "" | Some d -> sprintf "-u %d " d) + (match gid with None -> "" | Some g -> sprintf "-g %d " g) + home username + @@ (match sudo with + | false -> empty + | true -> + let sudofile = "/etc/sudoers.d/" ^ username in + copy_heredoc + ~src:[ heredoc ~strip:true "\t%s %s" username sudo_nopasswd ] + ~dst:sudofile () + @@ run "chmod 440 %s" sudofile + @@ run "chown root:root %s" sudofile) + @@ user "%s" username @@ workdir "%s" home @@ run "mkdir .ssh" + @@ run "chmod 700 .ssh" + + let install_system_ocaml = run "pacman add ocaml ocaml-compiler-libs" +end diff --git a/src-opam/dockerfile_linux.mli b/src-opam/linux.mli similarity index 100% rename from src-opam/dockerfile_linux.mli rename to src-opam/linux.mli diff --git a/src-opam/windows.ml b/src-opam/windows.ml new file mode 100644 index 00000000..c6781844 --- /dev/null +++ b/src-opam/windows.ml @@ -0,0 +1,329 @@ +(* + * Copyright (c) 2020 - 2021 Tarides - Antonin Décimo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *) + +open Dockerfile +open Printf + +let run_cmd fmt = ksprintf (run "cmd /S /C %s") fmt + +let run_powershell ?(escape = Fun.id) fmt = + ksprintf (fun s -> run {|powershell -Command "%s"|} (escape s)) fmt + +let run_vc ~arch fmt = + let arch = + match arch with + | `I386 -> "x86" + | `X86_64 -> "amd64" + | `Aarch64 | `Aarch32 | `Ppc64le | `S390x | `Riscv64 -> + invalid_arg "Unsupported architecture" + in + ksprintf + (run {|cd C:\BuildTools\VC\Auxiliary\Build && vcvarsall.bat %s && %s|} arch) + fmt + +let run_ocaml_env args fmt = + ksprintf (run {|ocaml-env exec %s -- %s|} (String.concat " " args)) fmt + +let install_vc_redist ?(vs_version = "16") () = + add + ~src:[ "https://aka.ms/vs/" ^ vs_version ^ "/release/vc_redist.x64.exe" ] + ~dst:{|C:\TEMP\|} () + @@ run + {|C:\TEMP\vc_redist.x64.exe /install /passive /norestart /log C:\TEMP\vc_redist.log|} + +let install_visual_studio_build_tools ?(vs_version = "16") components = + let install = + let fmt = + format_of_string + {|C:\TEMP\Install.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ` + --installPath C:\BuildTools --channelUri C:\TEMP\VisualStudio.chman ` + --installChannelUri C:\TEMP\VisualStudio.chman%s|} + in + run fmt + (List.fold_left + (fun acc component -> acc ^ " `\n --add " ^ component) + "" components) + in + (* https://docs.microsoft.com/en-us/visualstudio/install/advanced-build-tools-container?view=vs-2019#install-script *) + add + ~src: + [ + "https://raw.githubusercontent.com/avsm/ocaml-dockerfile/master/src-opam/Install.cmd"; + ] + ~dst:{|C:\TEMP\|} () + @@ add ~src:[ "https://aka.ms/vscollect.exe" ] ~dst:{|C:\TEMP\collect.exe|} () + @@ add + ~src:[ "https://aka.ms/vs/" ^ vs_version ^ "/release/channel" ] + ~dst:{|C:\TEMP\VisualStudio.chman|} () + @@ add + ~src:[ "https://aka.ms/vs/" ^ vs_version ^ "/release/vs_buildtools.exe" ] + ~dst:{|C:\TEMP\vs_buildtools.exe|} () + @@ install + +let sanitize_reg_path () = + run + {|for /f "tokens=1,2,*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path ^| findstr /r "\\$"') do ` + for /f "delims=" %%l in ('cmd /v:on /c "set v=%%c&& echo !v:~0,-1!"') do ` + reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path /t REG_EXPAND_SZ /f /d "%%l"|} + +let prepend_path paths = + let paths = String.concat ";" paths in + run + {|for /f "tokens=1,2,*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path ^| findstr /r "^[^H]"') do ` + reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path /t REG_EXPAND_SZ /f /d "%s;%%c"|} + paths + +let ocaml_for_windows_package_exn ~switch ~port ~arch = + let variant = + let bitness = if Ocaml_version.arch_is_32bit arch then "32" else "64" in + match arch with + | `X86_64 | `I386 -> + (match port with `Mingw -> "mingw" | `Msvc -> "msvc") ^ bitness + | _ -> invalid_arg "Unsupported architecture" + in + let _, pkgver = Ocaml_version.Opam.V2.package switch in + ("ocaml-variants", pkgver ^ "+" ^ variant) + +let cleanup () = run_powershell {|Remove-Item 'C:\TEMP' -Recurse|} + +let git_init ~name ~email ~opam_repository = + String.concat " && " + [ + sprintf "git config --global user.email '%s'" email; + sprintf "git config --global user.name '%s'" name; + "git config --system core.longpaths true"; + sprintf "git config --global --add safe.directory %s" opam_repository; + ] + +module Cygwin = struct + type cyg = { root : string; site : string; args : string list } + + let cygsetup = {|C:\cygwin-setup-x86_64.exe|} + let cygcache = {|C:\TEMP\cache|} + + let default = + { + root = {|C:\cygwin64|}; + site = "https://mirrors.kernel.org/sourceware/cygwin/"; + args = + [ + "--quiet-mode"; + "--no-shortcuts"; + "--no-startmenu"; + "--no-desktop"; + "--only-site"; + "--local-package-dir"; + cygcache; + ]; + } + + let run_sh ?(cyg = default) fmt = + ksprintf (run {|%s\bin\bash.exe --login -c "%s"|} cyg.root) fmt + + let run_sh_ocaml_env ?(cyg = default) args fmt = + ksprintf + (run_sh ~cyg "ocaml-env exec %s -- %s" (String.concat " " args)) + fmt + + let install_cygsympathy_from_source cyg = + run {|mkdir %s\lib\cygsympathy && mkdir %s\etc\postinstall|} cyg.root + cyg.root + @@ add + ~src: + [ + "https://raw.githubusercontent.com/metastack/cygsympathy/master/cygsympathy.cmd"; + ] + ~dst:(cyg.root ^ {|\lib\cygsympathy\|}) + () + @@ add + ~src: + [ + "https://raw.githubusercontent.com/metastack/cygsympathy/master/cygsympathy.sh"; + ] + ~dst:(cyg.root ^ {|\lib\cygsympathy\cygsympathy|}) + () + (* Beware: CygSymPathy must be executed last, or it may miss files + installed by other post-install scripts. Use a name that is + greater than every other script in the lexicographic order. *) + @@ run + {|mklink %s\etc\postinstall\zp_zcygsympathy.sh %s\lib\cygsympathy\cygsympathy|} + cyg.root cyg.root + + let install_msvs_tools_from_source ?(version = "0.4.1") cyg = + add + ~src: + [ + "https://github.com/metastack/msvs-tools/archive/" ^ version + ^ ".tar.gz"; + ] + ~dst:{|C:\TEMP\msvs-tools.tar.gz|} () + @@ run_sh ~cyg + {|cd /tmp && tar -xf /cygdrive/c/TEMP/msvs-tools.tar.gz && cp msvs-tools-%s/msvs-detect msvs-tools-%s/msvs-promote-path /bin|} + version version + + let cygwin ?(cyg = default) fmt = + ksprintf + (run {|%s %s --root %s --site %s --symlink-type=wsl %s|} cygsetup + (String.concat " " cyg.args) + cyg.root cyg.site) + fmt + + let install ?(cyg = default) fmt = ksprintf (cygwin ~cyg "--packages %s") fmt + + let setup ?(cyg = default) ?(winsymlinks_native = true) ?(extra = []) () = + (if winsymlinks_native then env [ ("CYGWIN", "winsymlinks:native") ] + else empty) + @@ add + ~src:[ "https://www.cygwin.com/setup-x86_64.exe" ] + ~dst:{|C:\cygwin-setup-x86_64.exe|} () + @@ install_cygsympathy_from_source cyg + @@ cygwin ~cyg "--packages %s" + (extra |> List.sort_uniq String.compare |> String.concat ",") + @@ install_msvs_tools_from_source cyg + @@ prepend_path (List.map (( ^ ) cyg.root) [ {|\bin|} ]) + @@ run + {|awk -i inplace "/(^#)|(^$)/{print;next}{$4=""noacl,""$4; print}" %s\etc\fstab|} + cyg.root + @@ workdir {|%s\home\opam|} cyg.root + + let update ?(cyg = default) () = + run {|%s %s --root %s --site %s --upgrade-also|} cygsetup + (String.concat " " cyg.args) + cyg.root cyg.site + + let cygwin_packages ?(extra = []) ?(flexdll_version = "0.39-1") () = + (* 2021-03-19: flexdll 0.39 is required, but is in Cygwin testing *) + "make" :: "diffutils" :: "ocaml" :: "gcc-core" :: "git" :: "patch" :: "m4" + :: "cygport" + :: ("flexdll=" ^ flexdll_version) + :: extra + + let mingw_packages ?(extra = []) () = + "make" :: "diffutils" :: "mingw64-x86_64-gcc-core" :: extra + + let msvc_packages ?(extra = []) () = "make" :: "diffutils" :: extra + + let ocaml_for_windows_packages ?cyg ?(extra = []) ?(version = "0.0.0.2") () = + let packages = + "make" :: "diffutils" :: "mingw64-x86_64-gcc-g++" :: "vim" :: "git" + :: "curl" :: "rsync" :: "unzip" :: "patch" :: "m4" :: extra + in + let t = + add + ~src: + [ + "https://github.com/fdopen/opam-repository-mingw/releases/download/" + ^ version ^ "/opam64.tar.xz"; + ] + ~dst:{|C:\TEMP\|} () + @@ run_sh ?cyg + {|cd /tmp && tar -xf /cygdrive/c/TEMP/opam64.tar.xz && ./opam64/install.sh --prefix=/usr && rm -rf opam64 opam64.tar.xz|} + in + (packages, t) + + module Git = struct + let init ?(cyg = default) ?(name = "Docker") ?(email = "docker@example.com") + () = + env [ ("HOME", cyg.root ^ {|\home\opam|}) ] + @@ run_sh ~cyg "%s" + (git_init ~email ~name ~opam_repository:"/home/opam/opam-repository") + end +end + +module Winget = struct + let is_supported version = + not + (List.mem version + [ + `V1507; `Ltsc2015; `V1511; `V1607; `Ltsc2016; `V1703; `V1709; `V1803; + ]) + + let winget = "winget-builder" + + let header ?win10_revision + ?(version = + (Distro.win10_latest_image : Distro.win10_release :> Distro.win_all)) () + = + let img, tag = Distro.win10_base_tag ?win10_revision `Windows version in + parser_directive (`Escape '`') + @@ from ~alias:winget ~tag img + @@ user "ContainerAdministrator" + + let footer path = + run {|mkdir "C:\Program Files\winget-cli"|} + @@ run + {|move "C:\TEMP\winget-cli\%s\winget.exe" "C:\Program Files\winget-cli\"|} + path + @@ run + {|move "C:\TEMP\winget-cli\%s\WindowsPackageManager.dll" "C:\Program Files\winget-cli\"|} + path + @@ run + {|move "C:\TEMP\winget-cli\%s\resources.pri" "C:\Program Files\winget-cli\"|} + path + |> crunch + + let install_from_release ?win10_revision ?version ?winget_version () = + let file = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe." in + let src = + let src = "https://github.com/microsoft/winget-cli/releases/" in + match winget_version with + | None -> src ^ "latest/download/" ^ file ^ "msixbundle" + | Some ver -> src ^ "download/" ^ ver ^ "/" ^ file ^ "msixbundle" + in + let dst = {|C:\TEMP\|} ^ file ^ "zip" in + header ?win10_revision ?version () + @@ add ~src:[ src ] ~dst () + @@ run_powershell + {|Expand-Archive -LiteralPath %s -DestinationPath C:\TEMP\winget-cli -Force|} + dst + @@ run {|ren C:\TEMP\winget-cli\AppInstaller_x64.msix AppInstaller_x64.zip|} + @@ run_powershell + {|Expand-Archive -LiteralPath C:\TEMP\winget-cli\AppInstaller_x64.zip -DestinationPath C:\TEMP\winget-cli\ -Force|} + @@ footer "" + + let setup ?(from = winget) () = + let escape s = String.(concat {|""""|} (split_on_char '"' s)) in + copy ~from + ~src:[ {|C:\Program Files\winget-cli|} ] + ~dst:{|C:\Program Files\winget-cli|} () + @@ prepend_path [ {|C:\Program Files\winget-cli|} ] + @@ run_powershell ~escape + {|$path=(Join-Path $env:LOCALAPPDATA 'Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState'); New-Item $path -ItemType Directory -Force; '{ "$schema": "https://aka.ms/winget-settings.schema.json", "telemetry": { "disable": "true" } }' | Out-File -encoding ASCII (Join-Path $path 'settings.json')|} + + let install pkgs = + List.fold_left + (fun acc pkg -> + acc + @@ run + "winget install --exact --accept-source-agreements \ + --accept-package-agreements %s" + pkg) + empty pkgs + + let dev_packages ?version ?extra () = + match version with + (* 2021-04-01: Installing git fails with exit-code 2316632065. *) + | Some `V1809 -> maybe install extra + | _ -> install [ "Git.Git" ] @@ maybe install extra + + module Git = struct + let init ?(name = "Docker") ?(email = "docker@example.com") () = + run "%s" + (git_init ~email ~name + ~opam_repository:"C:/cygwin64/home/opam/opam-repository") + end +end diff --git a/src-opam/dockerfile_windows.mli b/src-opam/windows.mli similarity index 84% rename from src-opam/dockerfile_windows.mli rename to src-opam/windows.mli index 5b849f92..2ce01c8f 100644 --- a/src-opam/dockerfile_windows.mli +++ b/src-opam/windows.mli @@ -22,8 +22,8 @@ open Dockerfile val run_cmd : ('a, unit, string, t) format4 -> 'a (** [run_cmd fmt] will execute [cmd /S /C fmt]. *) -val run_powershell : ?escape:(string -> string) -> - ('a, unit, string, t) format4 -> 'a +val run_powershell : + ?escape:(string -> string) -> ('a, unit, string, t) format4 -> 'a (** [run_powershell fmt] will execute [powershell -Command "fmt"]. @param escape (defaults to {!Fun.id}) allows to escape [fmt] @@ -53,8 +53,10 @@ val install_visual_studio_build_tools : ?vs_version:string -> string list -> t @see *) val ocaml_for_windows_package_exn : - switch:Ocaml_version.t -> port:[`Mingw | `Msvc] -> arch:Ocaml_version.arch -> - (string * string) + switch:Ocaml_version.t -> + port:[ `Mingw | `Msvc ] -> + arch:Ocaml_version.arch -> + string * string (** [ocaml_for_windows_variant ~port ~arch] returns the [(package_name, package_version)] of the OCaml compiler package in OCaml for Windows, if applicable. *) @@ -65,16 +67,18 @@ val cleanup : unit -> t (** Rules for Cygwin-based installation *) module Cygwin : sig type cyg = { - root : string; (** Root installation directory *) - site : string; (** Download site URL *) - args : string list; (** List of arguments to give to Cygwin's + root : string; (** Root installation directory *) + site : string; (** Download site URL *) + args : string list; + (** List of arguments to give to Cygwin's setup, except [--root] and [--site]. *) - } + } val default : cyg (** The default Cygwin root, mirror, and arguments. *) - val setup : ?cyg:cyg -> ?winsymlinks_native:bool -> ?extra:string list -> unit -> t + val setup : + ?cyg:cyg -> ?winsymlinks_native:bool -> ?extra:string list -> unit -> t (** Setup Cygwin with CygSymPathy and msvs-tools, and [extra] Cygwin packages. Sets the [CYGWIN=winsymlinks:native] environment variable by default. @@ -88,8 +92,8 @@ module Cygwin : sig val update : ?cyg:cyg -> unit -> t (** Update Cygwin packages. *) - val cygwin_packages : ?extra:string list -> ?flexdll_version:string -> unit - -> string list + val cygwin_packages : + ?extra:string list -> ?flexdll_version:string -> unit -> string list (** [cygwin_packages ?extra ()] will install the base development tools for the OCaml Cygwin port. Extra packages may also be optionally supplied via [extra]. *) @@ -104,8 +108,8 @@ module Cygwin : sig tools for the OCaml MSVC port. Extra packages may also be optionally supplied via [extra]. *) - val ocaml_for_windows_packages : ?cyg:cyg -> ?extra:string list -> ?version:string -> unit - -> string list * t + val ocaml_for_windows_packages : + ?cyg:cyg -> ?extra:string list -> ?version:string -> unit -> string list * t (** [ocaml_for_windows_packages ?extra ()] returns the list of Cygwin packages dependencies, and the installation instructions. Extra packages may also be optionally supplied via [extra]. @@ -115,7 +119,8 @@ module Cygwin : sig (** [run_sh ?cyg fmt] will execute in the Cygwin root [\bin\bash.exe --login -c "fmt"]. *) - val run_sh_ocaml_env : ?cyg:cyg -> string list -> ('a, unit, string, t) format4 -> 'a + val run_sh_ocaml_env : + ?cyg:cyg -> string list -> ('a, unit, string, t) format4 -> 'a (** [run_cmd_ocaml_env args fmt] will execute [fmt] in the evironment loaded by [ocaml-env cygwin exec] with [args]. *) @@ -129,14 +134,17 @@ end (** Rules for winget installation. @see / *) module Winget : sig - val is_supported : Dockerfile_distro.win_all -> bool + val is_supported : Distro.win_all -> bool (** Winget 1.0.11692 discontinued support for versions older than Windows 10 1809. Older versions of Winget have bugs, don't use them. *) val install_from_release : - ?win10_revision:Dockerfile_distro.win10_lcu -> - ?version:Dockerfile_distro.win_all -> ?winget_version:string -> unit -> t + ?win10_revision:Distro.win10_lcu -> + ?version:Distro.win_all -> + ?winget_version:string -> + unit -> + t (** Install winget from a released build (first in a separate Docker image). The optional [winget_version] specifies a Git tag. *) @@ -147,9 +155,7 @@ module Winget : sig val install : string list -> t (** [install packages] will install the supplied winget package list. *) - val dev_packages : - ?version:Dockerfile_distro.win_all -> - ?extra:string list -> unit -> t + val dev_packages : ?version:Distro.win_all -> ?extra:string list -> unit -> t (** [dev_packages ?version ?extra ()] will install the base development tools. Extra packages may also be optionally supplied via [extra]. Using [?version] may change the set of installed packages. *) diff --git a/src/dockerfile.ml b/src/dockerfile.ml index 85d67520..ad068712 100644 --- a/src/dockerfile.ml +++ b/src/dockerfile.ml @@ -18,32 +18,38 @@ open Sexplib.Conv type shell_or_exec = - [`Shell of string | `Shells of string list | `Exec of string list] - [@@deriving sexp] + [ `Shell of string | `Shells of string list | `Exec of string list ] +[@@deriving sexp] type sources_to_dest = - [`From of string option] * [`Src of string list] * [`Dst of string] * [`Chown of string option] * [`Link of bool option] - [@@deriving sexp] + [ `From of string option ] + * [ `Src of string list ] + * [ `Dst of string ] + * [ `Chown of string option ] + * [ `Link of bool option ] +[@@deriving sexp] type from = { image : string; - tag: string option; - alias: string option; - platform: string option } [@@deriving sexp] + tag : string option; + alias : string option; + platform : string option; +} +[@@deriving sexp] -type parser_directive = - [ `Syntax of string | `Escape of char ] - [@@deriving sexp] +type parser_directive = [ `Syntax of string | `Escape of char ] +[@@deriving sexp] type heredoc = { - here_document: string; - word: string; - delimiter: string; - strip: bool } [@@deriving sexp] + here_document : string; + word : string; + delimiter : string; + strip : bool; +} +[@@deriving sexp] -type heredocs_to_dest = - [`Chown of string option] * heredoc list * string - [@@deriving sexp] +type heredocs_to_dest = [ `Chown of string option ] * heredoc list * string +[@@deriving sexp] type line = [ `ParserDirective of parser_directive @@ -64,16 +70,13 @@ type line = | `Workdir of string | `Onbuild of line | `Label of (string * string) list ] - [@@deriving sexp] +[@@deriving sexp] type t = line list [@@deriving sexp] let ( @@ ) = ( @ ) - let ( @@@ ) = List.fold_left (fun a b -> a @@ b) - let empty = [] - let maybe f = function None -> empty | Some v -> f v open Printf @@ -84,11 +87,11 @@ let crunch l = let pack l = let rec aux acc = function | [] -> acc - | (`Run `Shell a) :: (`Run `Shell b) :: tl -> - aux (`Run (`Shells [a; b]) :: acc) tl - | (`Run `Shells a) :: (`Run `Shell b) :: tl -> - aux (`Run (`Shells (a @ [b])) :: acc) tl - | (`Run `Shells a) :: (`Run `Shells b) :: tl -> + | `Run (`Shell a) :: `Run (`Shell b) :: tl -> + aux (`Run (`Shells [ a; b ]) :: acc) tl + | `Run (`Shells a) :: `Run (`Shell b) :: tl -> + aux (`Run (`Shells (a @ [ b ])) :: acc) tl + | `Run (`Shells a) :: `Run (`Shells b) :: tl -> aux (`Run (`Shells (a @ b)) :: acc) tl | hd :: tl -> aux (hd :: acc) tl in @@ -100,86 +103,83 @@ let crunch l = in fixp pack l - let quote s = sprintf "%S" s - let cmd c r = c ^ " " ^ r let json_array_of_list sl = sprintf "[ %s ]" (String.concat ", " (List.map quote sl)) - -let string_of_shell_or_exec ~escape (t: shell_or_exec) = +let string_of_shell_or_exec ~escape (t : shell_or_exec) = match t with | `Shell s -> s | `Shells [] -> "" - | `Shells [s] -> s - | `Shells l -> String.concat (" && "^(String.make 1 escape)^"\n ") l + | `Shells [ s ] -> s + | `Shells l -> String.concat (" && " ^ String.make 1 escape ^ "\n ") l | `Exec sl -> json_array_of_list sl - let string_of_env_list ~escape el = let quote v = let len = String.length v in let buf = Buffer.create len in let j = ref 0 in for i = 0 to len - 1 do - if v.[i] = '"' || v.[i] = escape then begin + if v.[i] = '"' || v.[i] = escape then ( if i - !j > 0 then Buffer.add_substring buf v !j (i - !j); Buffer.add_char buf escape; - j := i - end + j := i) done; Buffer.add_substring buf v !j (len - !j); Buffer.contents buf in - String.concat " " (List.map (fun (k, v) -> sprintf {|%s="%s"|} k (quote v)) el) - + String.concat " " + (List.map (fun (k, v) -> sprintf {|%s="%s"|} k (quote v)) el) let optional name = function | None -> [] - | Some value -> [sprintf "%s=%s" name value] + | Some value -> [ sprintf "%s=%s" name value ] let optional_flag name = function - | Some true -> [name] + | Some true -> [ name ] | Some false | None -> [] -let string_of_sources_to_dest (t: sources_to_dest) = +let string_of_sources_to_dest (t : sources_to_dest) = let `From frm, `Src sl, `Dst d, `Chown chown, `Link link = t in - String.concat " " ( - optional_flag "--link" link - @ optional "--chown" chown - @ optional "--from" frm - @ [json_array_of_list (sl @ [d])]) + String.concat " " + (optional_flag "--link" link + @ optional "--chown" chown @ optional "--from" frm + @ [ json_array_of_list (sl @ [ d ]) ]) let string_of_label_list ls = List.map (fun (k, v) -> sprintf "%s=%S" k v) ls |> String.concat " " -let string_of_copy_heredoc (t: heredocs_to_dest) = +let string_of_copy_heredoc (t : heredocs_to_dest) = let `Chown chown, heredocs, dst = t in let header, docs = - List.fold_left (fun (header, docs) t -> - (sprintf "<<%s%s" (if t.strip then "-" else "") t.word) :: header, - sprintf "%s\n%s\n%s" docs t.here_document t.delimiter) - ([], "") heredocs in - String.concat " " ( - optional "--chown" chown - @ (List.rev header) - @ [dst]) + List.fold_left + (fun (header, docs) t -> + ( sprintf "<<%s%s" (if t.strip then "-" else "") t.word :: header, + sprintf "%s\n%s\n%s" docs t.here_document t.delimiter )) + ([], "") heredocs + in + String.concat " " (optional "--chown" chown @ List.rev header @ [ dst ]) ^ docs -let rec string_of_line ~escape (t: line) = +let rec string_of_line ~escape (t : line) = match t with - | `ParserDirective (`Escape c) -> - cmd "#" ("escape="^(String.make 1 c)) - | `ParserDirective (`Syntax str) -> cmd "#" ("syntax="^str) + | `ParserDirective (`Escape c) -> cmd "#" ("escape=" ^ String.make 1 c) + | `ParserDirective (`Syntax str) -> cmd "#" ("syntax=" ^ str) | `Comment c -> cmd "#" c - | `From {image; tag; alias; platform} -> - cmd "FROM" (String.concat "" [ - (match platform with None -> "" | Some p -> "--platform="^p^" "); - image; - (match tag with None -> "" | Some t -> ":"^t); - (match alias with None -> "" | Some a -> " as " ^ a)]) + | `From { image; tag; alias; platform } -> + cmd "FROM" + (String.concat "" + [ + (match platform with + | None -> "" + | Some p -> "--platform=" ^ p ^ " "); + image; + (match tag with None -> "" | Some t -> ":" ^ t); + (match alias with None -> "" | Some a -> " as " ^ a); + ]) | `Maintainer m -> cmd "MAINTAINER" m | `Run c -> cmd "RUN" (string_of_shell_or_exec ~escape c) | `Cmd c -> cmd "CMD" (string_of_shell_or_exec ~escape c) @@ -196,57 +196,41 @@ let rec string_of_line ~escape (t: line) = | `Onbuild t -> cmd "ONBUILD" (string_of_line ~escape t) | `Label ls -> cmd "LABEL" (string_of_label_list ls) - (* Function interface *) -let parser_directive pd : t = [`ParserDirective pd] - -let heredoc ?(strip=false) ?(word="EOF") ?(delimiter=word) fmt = - ksprintf (fun here_document -> { here_document; strip; word; delimiter; }) fmt - -let from ?alias ?tag ?platform image = - [`From { image; tag; alias; platform }] - -let comment fmt = ksprintf (fun c -> [`Comment c]) fmt - -let maintainer fmt = ksprintf (fun m -> [`Maintainer m]) fmt +let parser_directive pd : t = [ `ParserDirective pd ] -let run fmt = ksprintf (fun b -> [`Run (`Shell b)]) fmt +let heredoc ?(strip = false) ?(word = "EOF") ?(delimiter = word) fmt = + ksprintf (fun here_document -> { here_document; strip; word; delimiter }) fmt -let run_exec cmds : t = [`Run (`Exec cmds)] +let from ?alias ?tag ?platform image = [ `From { image; tag; alias; platform } ] +let comment fmt = ksprintf (fun c -> [ `Comment c ]) fmt +let maintainer fmt = ksprintf (fun m -> [ `Maintainer m ]) fmt +let run fmt = ksprintf (fun b -> [ `Run (`Shell b) ]) fmt +let run_exec cmds : t = [ `Run (`Exec cmds) ] +let cmd fmt = ksprintf (fun b -> [ `Cmd (`Shell b) ]) fmt +let cmd_exec cmds : t = [ `Cmd (`Exec cmds) ] +let expose_port p : t = [ `Expose [ p ] ] +let expose_ports p : t = [ `Expose p ] +let env e : t = [ `Env e ] -let cmd fmt = ksprintf (fun b -> [`Cmd (`Shell b)]) fmt +let add ?link ?chown ?from ~src ~dst () : t = + [ `Add (`From from, `Src src, `Dst dst, `Chown chown, `Link link) ] -let cmd_exec cmds : t = [`Cmd (`Exec cmds)] +let copy ?link ?chown ?from ~src ~dst () : t = + [ `Copy (`From from, `Src src, `Dst dst, `Chown chown, `Link link) ] -let expose_port p : t = [`Expose [p]] - -let expose_ports p : t = [`Expose p] - -let env e : t = [`Env e] - -let add ?link ?chown ?from ~src ~dst () : t = [`Add (`From from, `Src src, `Dst dst, `Chown chown, `Link link)] - -let copy ?link ?chown ?from ~src ~dst () : t = [`Copy (`From from, `Src src, `Dst dst, `Chown chown, `Link link)] - -let copy_heredoc ?chown ~src ~dst () : t = [`Copy_heredoc (`Chown chown, src, dst)] - -let user fmt = ksprintf (fun u -> [`User u]) fmt +let copy_heredoc ?chown ~src ~dst () : t = + [ `Copy_heredoc (`Chown chown, src, dst) ] +let user fmt = ksprintf (fun u -> [ `User u ]) fmt let onbuild t = List.map (fun l -> `Onbuild l) t - -let volume fmt = ksprintf (fun v -> [`Volume [v]]) fmt - -let volumes v : t = [`Volume v] - -let label ls = [`Label ls] - -let entrypoint fmt = ksprintf (fun e -> [`Entrypoint (`Shell e)]) fmt - -let entrypoint_exec e : t = [`Entrypoint (`Exec e)] - -let shell s : t = [`Shell s] - -let workdir fmt = ksprintf (fun wd -> [`Workdir wd]) fmt +let volume fmt = ksprintf (fun v -> [ `Volume [ v ] ]) fmt +let volumes v : t = [ `Volume v ] +let label ls = [ `Label ls ] +let entrypoint fmt = ksprintf (fun e -> [ `Entrypoint (`Shell e) ]) fmt +let entrypoint_exec e : t = [ `Entrypoint (`Exec e) ] +let shell s : t = [ `Shell s ] +let workdir fmt = ksprintf (fun wd -> [ `Workdir wd ]) fmt let string_of_t tl = let rec find_escape = function diff --git a/src/dockerfile.mli b/src/dockerfile.mli index 90ae6f3f..f8b8fe23 100644 --- a/src/dockerfile.mli +++ b/src/dockerfile.mli @@ -21,8 +21,8 @@ (** {2 Core combinators and serializers} *) -(** [t] is a list of Dockerfile lines *) type t +(** [t] is a list of Dockerfile lines *) val sexp_of_t : t -> Sexplib.Sexp.t (** [sexp_of_t t] converts a Dockerfile into a s-expression representation. *) @@ -52,9 +52,8 @@ val maybe : ('a -> t) -> 'a option -> t (** {2 Dockerfile commands} *) -type parser_directive = - [ `Syntax of string | `Escape of char ] - [@@deriving sexp] +type parser_directive = [ `Syntax of string | `Escape of char ] +[@@deriving sexp] val parser_directive : parser_directive -> t (** A parser directive. If used, needs to be the first line of the @@ -67,7 +66,12 @@ val comment : ('a, unit, string, t) format4 -> 'a type heredoc (** Build here-document values with {!val:heredoc}. *) -val heredoc : ?strip:bool -> ?word:string -> ?delimiter:string -> ('a, unit, string, heredoc) format4 -> 'a +val heredoc : + ?strip:bool -> + ?word:string -> + ?delimiter:string -> + ('a, unit, string, heredoc) format4 -> + 'a (** [heredoc ~word here_document] creates a {!type:heredoc} value with [here_document] as content and [word] () as opening delimiter. If [word] is quoted, then [delimiter] (unquoted [word]) needs to be @@ -156,7 +160,14 @@ val env : (string * string) list -> t instructions. This is functionally equivalent to prefixing a shell command with [=]. *) -val add : ?link:bool -> ?chown:string -> ?from:string -> src:string list -> dst:string -> unit -> t +val add : + ?link:bool -> + ?chown:string -> + ?from:string -> + src:string list -> + dst:string -> + unit -> + t (** [add ?link ?chown ?from ~src ~dst ()] copies new files, directories or remote file URLs from [src] and adds them to the filesystem of the container at the [dst] path. @@ -191,7 +202,14 @@ val add : ?link:bool -> ?chown:string -> ?from:string -> src:string list -> dst: the first {!from} stage, or a named stage (supplied via [?alias] to the {!from} command). *) -val copy : ?link:bool -> ?chown:string -> ?from:string -> src:string list -> dst:string -> unit -> t +val copy : + ?link:bool -> + ?chown:string -> + ?from:string -> + src:string list -> + dst:string -> + unit -> + t (** [copy ?link ?chown ?from ~src ~dst ()] copies new files or directories from [src] and adds them to the filesystem of the container at the path [dst]. See {!add} for more detailed @@ -210,7 +228,7 @@ val copy : ?link:bool -> ?chown:string -> ?from:string -> src:string list -> dst the first {!from} stage, or a named stage (supplied via [?alias] to the {!from} command). *) -val copy_heredoc : ?chown:string -> src:(heredoc list) -> dst:string -> unit -> t +val copy_heredoc : ?chown:string -> src:heredoc list -> dst:string -> unit -> t (** [copy_heredoc src dst] creates the file [dst] using the content of the here-documents [src]. Requires BuildKit 1.4 {{!val:parser_directive}syntax}.