diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a4b06d2..69d6ee3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,29 +1,20 @@ -FROM ocaml/opam:debian-12-ocaml-4.14 +FROM ocaml/opam:debian-12-ocaml-5.3 +COPY --from=hadolint/hadolint:latest-alpine /bin/hadolint /bin/hadolint USER root -# copy hadolint -COPY --from=hadolint/hadolint:latest-alpine /bin/hadolint /bin/hadolint - # Avoid warnings by switching to noninteractive -ENV DEBIAN_FRONTEND noninteractive -ENV SIHL_ENV development +ENV DEBIAN_FRONTEND=noninteractive # install packages +# hadolint ignore=DL3008 RUN apt-get update -q && apt-get install -yqq --no-install-recommends \ # development dependencies inotify-tools \ - zsh \ - m4 \ - wget \ - # - # build dependencies (would also be installed by opam depext) - gcc \ - jq \ - libev-dev \ libgmp-dev \ - libssl-dev \ pkg-config \ + wget \ + zsh \ # # cleanup installations && apt-get autoremove -y \ @@ -33,9 +24,9 @@ RUN apt-get update -q && apt-get install -yqq --no-install-recommends \ # add timezone RUN ln -fs /usr/share/zoneinfo/Europe/Zurich /etc/localtime -# WTF: https://github.com/mirage/ocaml-cohttp/issues/675 -RUN bash -c 'echo "http 80/tcp www # WorldWideWeb HTTP" >> /etc/services' \ - && bash -c 'echo "https 443/tcp www # WorldWideWeb HTTPS" >> /etc/services' +# link opam version +# hadolint ignore=DL3059 +RUN ln -fs /usr/bin/opam-2.2 /usr/bin/opam USER opam diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 19e844d..1e9f728 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,14 +1,10 @@ -// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at -// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/python-3 or the -// devcontainer docu https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference { "name": "letters", "dockerComposeFile": "./docker-compose.yml", "service": "dev", "workspaceFolder": "/workspace", "privileged": true, - "postCreateCommand": "/bin/bash .devcontainer/postCreate.sh", - // Supported customizations: https://containers.dev/supporting + "postCreateCommand": ".devcontainer/postCreate.sh", "customizations": { "vscode": { "settings": { @@ -27,7 +23,6 @@ "kind": "global" } }, - // Add the IDs of extensions you want installed when the container is created in the array below. "extensions": [ "donjayamanne.githistory", "eamodio.gitlens", diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index fb29637..5aaa42e 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -10,14 +10,19 @@ services: - ..:/workspace:cached - opam:/home/opam/.opam:cached - build:/workspace/_build:cached - - ${HOME}${USERPROFILE}/.ssh:/home/opam/.ssh - - ${HOME}${USERPROFILE}/.gitconfig:/home/opam/.gitconfig - - ${HOME}${USERPROFILE}/.gitignore_global:/home/opam/.gitignore_global environment: - - OPAMSOLVERTIMEOUT=180 - - VERSION=dev + OPAMSOLVERTIMEOUT: 180 + VERSION: dev command: sleep infinity + mailtrap: + image: mailhog/mailhog + container_name: mailtrap-letters + hostname: mailtrap-letters + ports: + - "1025:1025" # SMTP server + - "8025:8025" # Web UI + volumes: opam: build: diff --git a/.devcontainer/postCreate.sh b/.devcontainer/postCreate.sh old mode 100644 new mode 100755 index 6c7a1f2..541ddee --- a/.devcontainer/postCreate.sh +++ b/.devcontainer/postCreate.sh @@ -3,19 +3,8 @@ # immediately when a command fails and print each command set -ex -# When possible to create cached docker volume, sudo chown -R opam: _build opam init -a --shell=zsh -# get newest opam packages -opam remote remove --all default -opam remote add default https://opam.ocaml.org - -opam pin add -yn letters . -opam depext -y letters - -# install opam packages used for vscode ocaml platform package -# e.g. when developing with emax, add also: utop merlin ocamlformat -opam install -y ocaml-lsp-server make deps diff --git a/.gitignore b/.gitignore index 04c7029..ea34577 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .merlin *_account.json .vscode +.env +.DS_Store diff --git a/Makefile b/Makefile index 1f745db..358355a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: deps deps: ## Install development dependencies - opam install --deps-only --with-test --with-doc -y . + opam install --working-dir --with-dev-setup --with-test --with-doc --update-invariant -y . eval $(opam env) .PHONY: create_switch diff --git a/dune-project b/dune-project index c099a60..33b5163 100644 --- a/dune-project +++ b/dune-project @@ -68,6 +68,7 @@ ;; Documentation dependencies (odoc :with-doc) ;; Dev dependencies - (ocamlformat :dev))) + (ocamlformat :with-dev-setup) + (ocaml-lsp-server :with-dev-setup))) (implicit_transitive_deps false) diff --git a/letters.opam b/letters.opam index 6186b24..8a6fc38 100644 --- a/letters.opam +++ b/letters.opam @@ -28,7 +28,8 @@ depends: [ "alcotest-lwt" {>= "1.1.0" & with-test} "yojson" {>= "1.7.0" & with-test} "odoc" {with-doc} - "ocamlformat" {dev} + "ocamlformat" {with-dev-setup} + "ocaml-lsp-server" {with-dev-setup} ] build: [ ["dune" "subst"] {dev} diff --git a/letters.opam.locked b/letters.opam.locked deleted file mode 100644 index 75e4376..0000000 --- a/letters.opam.locked +++ /dev/null @@ -1,97 +0,0 @@ -opam-version: "2.0" -version: "0.4.0" -synopsis: "Client library for sending emails over SMTP" -description: "Simple to use SMTP client implementation for OCaml" -maintainer: ["Miko Nieminen "] -authors: ["Miko Nieminen"] -license: "MIT" -homepage: "https://github.com/oxidizing/letters/" -doc: "https://oxidizing.github.io/letters/" -bug-reports: "https://github.com/oxidizing/letters/issues" -depends: [ - "angstrom" {= "0.16.1"} - "asn1-combinators" {= "0.3.2"} - "astring" {= "0.8.5"} - "base-bytes" {= "base"} - "base-threads" {= "base"} - "base-unix" {= "base"} - "base64" {= "3.5.1"} - "bigarray-overlap" {= "0.2.1"} - "bigstringaf" {= "0.10.0"} - "bos" {= "0.2.1"} - "ca-certs" {= "1.0.0"} - "cmdliner" {= "1.3.0"} - "coin" {= "0.1.4"} - "colombe" {= "0.11.0"} - "conf-gmp" {= "4"} - "conf-gmp-powm-sec" {= "3"} - "conf-pkg-config" {= "3"} - "containers" {= "3.15"} - "cppo" {= "1.8.0"} - "csexp" {= "1.5.2"} - "cstruct" {= "6.2.0"} - "digestif" {= "1.2.0"} - "domain-name" {= "0.4.0"} - "dune" {= "3.17.0"} - "dune-configurator" {= "3.17.0"} - "duration" {= "0.2.1"} - "either" {= "1.0.0"} - "emile" {= "1.1"} - "eqaf" {= "0.10"} - "fmt" {= "0.9.0"} - "fpath" {= "0.7.3"} - "gmap" {= "0.3.0"} - "hxd" {= "0.3.3"} - "ipaddr" {= "5.6.0"} - "kdf" {= "1.0.0"} - "ke" {= "0.6"} - "logs" {= "0.7.0"} - "lwt" {= "5.9.0"} - "macaddr" {= "5.6.0"} - "mirage-crypto" {= "1.1.0"} - "mirage-crypto-ec" {= "1.1.0"} - "mirage-crypto-pk" {= "1.1.0"} - "mirage-crypto-rng" {= "1.1.0"} - "mirage-crypto-rng-lwt" {= "1.1.0"} - "mrmime" {= "0.6.1"} - "mtime" {= "2.1.0"} - "ocaml" {= "4.14.2"} - "ocaml-syntax-shims" {= "1.0.0"} - "ocamlbuild" {= "0.15.0"} - "ocamlfind" {= "1.9.6"} - "ocplib-endian" {= "1.2"} - "ohex" {= "0.2.0"} - "pecu" {= "0.7"} - "prettym" {= "0.0.3"} - "ptime" {= "1.2.0"} - "re" {= "1.12.0"} - "rosetta" {= "0.3.0"} - "rresult" {= "0.7.0"} - "sendmail" {= "0.11.0"} - "seq" {= "base"} - "tls" {= "1.0.4"} - "tls-lwt" {= "1.0.4"} - "topkg" {= "1.0.7"} - "unstrctrd" {= "0.4"} - "uutf" {= "1.0.3"} - "uuuu" {= "0.3.0"} - "x509" {= "1.0.5"} - "yuscii" {= "0.3.0"} - "zarith" {= "1.14"} -] -build: [ - ["dune" "subst"] {dev} - [ - "dune" - "build" - "-p" - name - "-j" - jobs - "@install" - "@runtest" {with-test} - "@doc" {with-doc} - ] -] -dev-repo: "git+https://github.com/oxidizing/letters.git" -name: "letters" diff --git a/lib/dune b/lib/dune index 03df11e..7ca553e 100644 --- a/lib/dune +++ b/lib/dune @@ -19,6 +19,7 @@ sendmail.starttls tls tls-lwt + unix x509)) (env diff --git a/lib/sendmail_handler.ml b/lib/sendmail_handler.ml index b646ef3..5905359 100644 --- a/lib/sendmail_handler.ml +++ b/lib/sendmail_handler.ml @@ -96,11 +96,14 @@ let run_with_starttls recipients mail_stream in - Lwt_scheduler.prj fiber) + Lwt.finalize + (fun () -> Lwt_scheduler.prj fiber) + (fun () -> Lwt_io.close ic >>= fun () -> Lwt_io.close oc)) ;; let run ~hostname ?port ~domain ?authentication ~tls_authenticator ~from ~recipients ~mail = + let open Lwt.Infix in let ( let* ) = Lwt_result.bind in let port = match port with @@ -129,5 +132,7 @@ let run ~hostname ?port ~domain ?authentication ~tls_authenticator ~from ~recipi recipients mail_stream in - Lwt_scheduler.prj fiber + Lwt.finalize + (fun () -> Lwt_scheduler.prj fiber) + (fun () -> Lwt_io.close ic >>= fun () -> Lwt_io.close oc) ;;