Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dependency on dockerfile #51

Merged
merged 1 commit into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions dune-project
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
(lang dune 2.7)

(name obuilder)
(formatting disabled)

(generate_opam_files true)

(source (github ocurrent/obuilder))
(authors "talex5@gmail.com")
(maintainers "talex5@gmail.com")
(documentation "https://ocurrent.github.io/obuilder/")

(package
(name obuilder)
(synopsis "Run build scripts for CI")
(description "OBuilder takes a build script (similar to a Dockerfile) and performs the steps in it in a sandboxed environment.")
(description
"OBuilder takes a build script (similar to a Dockerfile) and performs the steps in it in a sandboxed environment.")
(depends
lwt
astring
Expand All @@ -29,18 +26,16 @@
sqlite3
obuilder-spec
(ocaml (>= 4.10.0))
(alcotest-lwt :with-test)
))

(alcotest-lwt :with-test)))
(package
(name obuilder-spec)
(synopsis "Build specification format")
(description "A library for constructing, reading and writing OBuilder build specification files.")
(description
"A library for constructing, reading and writing OBuilder build specification files.")
(depends
(fmt (>= 0.8.9))
sexplib
astring
ppx_deriving
ppx_sexp_conv
(dockerfile (>= 6.6.0))
(ocaml (>= 4.10.0))
))
(ocaml (>= 4.10.0))))
98 changes: 56 additions & 42 deletions lib_spec/docker.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
open Dockerfile

type ctx = {
user : Spec.user;
}
Expand All @@ -12,49 +10,65 @@ let default_ctx = {
let pp_pair f (k, v) =
Fmt.pf f "%s=%s" k v

let wrap x =
x
|> String.split_on_char '\n'
|> List.map String.trim
|> String.concat " \\\n "

let of_op ~buildkit (acc, ctx) : Spec.op -> Dockerfile.t list * ctx = function
| `Comment x -> comment "%s" x :: acc, ctx
| `Workdir x -> workdir "%s" x :: acc, ctx
| `Shell xs -> shell xs :: acc, ctx
| `Run { cache = (_ :: _) as cache; shell; network = _ } when buildkit ->
let mounts =
cache |> List.map (fun { Cache.id; target; buildkit_options } ->
let buildkit_options =
("--mount=type", "cache") ::
("id", id) ::
("target", target) ::
("uid", string_of_int ctx.user.uid) ::
buildkit_options
in
Fmt.strf "@[<h>%a@]" Fmt.(list ~sep:(unit ",") pp_pair) buildkit_options
)
in
run "%s %s" (String.concat " " mounts) (wrap shell) :: acc, ctx
| `Run { cache = _; network = _; shell } -> run "%s" (wrap shell) :: acc, ctx
| `Copy { from; src; dst; exclude = _ } ->
let from = match from with
| `Build name -> Some name
| `Context -> None
in
if ctx.user = Spec.root then copy ?from ~src ~dst () :: acc, ctx
let pp_wrap =
Fmt.using (String.split_on_char '\n')
Fmt.(list ~sep:(unit " \\@\n ") (using String.trim string))

let pp_cache ~ctx f { Cache.id; target; buildkit_options } =
let buildkit_options =
("--mount=type", "cache") ::
("id", id) ::
("target", target) ::
("uid", string_of_int ctx.user.uid) ::
buildkit_options
in
Fmt.pf f "%a" Fmt.(list ~sep:(unit ",") pp_pair) buildkit_options

let pp_run ~ctx f { Spec.cache; shell; network = _ } =
Fmt.pf f "RUN %a%a" Fmt.(list (pp_cache ~ctx ++ const string " ")) cache pp_wrap shell

let pp_copy ~ctx f { Spec.from; src; dst; exclude = _ } =
let from = match from with
| `Build name -> Some name
| `Context -> None
in
let chown =
if ctx.user = Spec.root then None
else (
let { Spec.uid; gid } = ctx.user in
let chown = Printf.sprintf "%d:%d" uid gid in
copy ?from ~chown ~src ~dst () :: acc, ctx
Some (Printf.sprintf "%d:%d" uid gid)
)
| `User ({ uid; gid } as u) -> user "%d:%d" uid gid :: acc, { user = u }
| `Env b -> env [b] :: acc, ctx
in
Fmt.pf f "COPY %a%a%a %s"
Fmt.(option (fmt "--chown=%s ")) chown
Fmt.(option (fmt "--from=%s ")) from
Fmt.(list ~sep:sp string) src
dst

let pp_op ~buildkit ctx f : Spec.op -> ctx = function
| `Comment x -> Fmt.pf f "# %s" x; ctx
| `Workdir x -> Fmt.pf f "WORKDIR %s" x; ctx
| `Shell xs -> Fmt.pf f "SHELL [ %a ]" Fmt.(list ~sep:comma (quote string)) xs; ctx
| `Run x when buildkit -> pp_run ~ctx f x; ctx
| `Run x -> pp_run ~ctx f { x with cache = [] }; ctx
| `Copy x -> pp_copy ~ctx f x; ctx
| `User ({ uid; gid } as u) -> Fmt.pf f "USER %d:%d" uid gid; { user = u }
| `Env (k, v) -> Fmt.pf f "ENV %s %s" k v; ctx

let rec convert ?name ~buildkit { Spec.child_builds; from; ops } =
let stages = child_builds |> List.map (fun (name, spec) -> convert ~name ~buildkit spec) |> List.flatten in
let ops', _ctx = List.fold_left (of_op ~buildkit) ([], default_ctx) ops in
stages @ [Dockerfile.from ?alias:name from @@@ List.rev ops']
let rec convert ~buildkit f (name, { Spec.child_builds; from; ops }) =
child_builds |> List.iter (fun (name, spec) ->
convert ~buildkit f (Some name, spec);
Format.pp_print_newline f ();
);
Fmt.pf f "@[<h>FROM %s%a@]@." from Fmt.(option (const string " as " ++ string)) name;
let (_ : ctx) = List.fold_left (fun ctx op ->
Format.pp_open_hbox f ();
let ctx = pp_op ~buildkit ctx f op in
Format.pp_close_box f ();
Format.pp_print_newline f ();
ctx
) default_ctx ops
in ()

let dockerfile_of_spec ~buildkit t =
Dockerfile.empty @@@ convert ~buildkit t
Fmt.strf "%a" (convert ~buildkit) (None, t)
2 changes: 1 addition & 1 deletion lib_spec/docker.mli
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
val dockerfile_of_spec : buildkit:bool -> Spec.t -> Dockerfile.t
val dockerfile_of_spec : buildkit:bool -> Spec.t -> string
(** [dockerfile_of_spec x] produces a Dockerfile that aims to be equivalent to [x].

However, note that:
Expand Down
2 changes: 1 addition & 1 deletion lib_spec/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
(name obuilder_spec)
(public_name obuilder-spec)
(preprocess (pps ppx_sexp_conv))
(libraries astring sexplib dockerfile))
(libraries astring sexplib fmt))
1 change: 0 additions & 1 deletion main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ let dockerfile buildkit spec =
Sexplib.Sexp.load_sexp spec
|> Obuilder_spec.t_of_sexp
|> Obuilder_spec.Docker.dockerfile_of_spec ~buildkit
|> Dockerfile.string_of_t
|> print_endline

open Cmdliner
Expand Down
2 changes: 1 addition & 1 deletion obuilder-spec.opam
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ doc: "https://ocurrent.github.io/obuilder/"
bug-reports: "https://github.com/ocurrent/obuilder/issues"
depends: [
"dune" {>= "2.7"}
"fmt" {>= "0.8.9"}
"sexplib"
"astring"
"ppx_deriving"
"ppx_sexp_conv"
"dockerfile" {>= "6.6.0"}
"ocaml" {>= "4.10.0"}
"odoc" {with-doc}
]
Expand Down
6 changes: 3 additions & 3 deletions test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -429,14 +429,13 @@ let remove_line_indents = function
let remove_indent s =
String.split_on_char '\n' s
|> remove_line_indents
|> List.filter ((<>) "")
|> String.concat "\n"


(* Check that parsing an S-expression and then serialising it again gets the same result. *)
let test_sexp () =
let test name s =
let s = remove_indent s in
let s = String.trim (remove_indent s) in
let s1 = Sexplib.Sexp.of_string s in
let spec = Spec.t_of_sexp s1 in
let s2 = Spec.sexp_of_t spec in
Expand All @@ -463,7 +462,7 @@ let test_sexp () =
let test_docker () =
let test ~buildkit name expect sexp =
let spec = Spec.t_of_sexp (Sexplib.Sexp.of_string sexp) in
let got = Obuilder_spec.Docker.dockerfile_of_spec ~buildkit spec |> Dockerfile.string_of_t in
let got = Obuilder_spec.Docker.dockerfile_of_spec ~buildkit spec in
let expect = remove_indent expect in
Alcotest.(check string) name expect got
in
Expand Down Expand Up @@ -528,6 +527,7 @@ let test_docker () =
test ~buildkit:false "Multi-stage"
{| FROM base as tools
RUN make tools

FROM base
COPY --from=tools binary /usr/local/bin/
|} {|
Expand Down