From a4870da9a4089b0ae594f780239ce2e0e3e6e82b Mon Sep 17 00:00:00 2001 From: anubhav-qt Date: Tue, 3 Nov 2026 10:57:45 +0530 Subject: [PATCH] Add dodo 0.0.1 --- recipes/dodo/recipe.yaml | 102 +++++++++++++++++++++++++ recipes/dodo/tests/hello_server.mojo | 16 ++++ recipes/dodo/tests/package_smoke.mojo | 103 ++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 recipes/dodo/recipe.yaml create mode 100644 recipes/dodo/tests/hello_server.mojo create mode 100644 recipes/dodo/tests/package_smoke.mojo diff --git a/recipes/dodo/recipe.yaml b/recipes/dodo/recipe.yaml new file mode 100644 index 00000000..de0fb151 --- /dev/null +++ b/recipes/dodo/recipe.yaml @@ -0,0 +1,102 @@ +context: + version: "0.0.1" + mojo_version: "=1.2.0" + +package: + name: dodo + version: ${{ version }} + +source: + - git: https://github.com/dodo-mojo/dodo.git + tag: v${{ version }} + +build: + number: 0 + script: + interpreter: bash + content: + - | + set -euo pipefail + mkdir -p "${PREFIX}/lib/mojo" + + # The wrapper build scripts install into $CONDA_PREFIX/lib, which + # here is the package prefix, and fail loudly on a broken build. + export CONDA_PREFIX="${PREFIX}" + export DODO_CC="${CC}" + export DODO_CXX="${CXX}" + source tools/build_native.sh + + mojo precompile dodo -o "${PREFIX}/lib/mojo/dodo.mojoc" + +requirements: + build: + - ${{ compiler('c') }} + - ${{ compiler('cxx') }} + - mojo-compiler ${{ mojo_version }} + host: + - mojo-compiler ${{ mojo_version }} + - openssl >=3.6.1,<4 + - zlib >=1.3.1,<2 + - libdeflate >=1.22,<2 + - libbrotlicommon >=1.2.1,<2 + - libbrotlidec >=1.2.1,<2 + - libbrotlienc >=1.2.1,<2 + - simdjson >=4.6.11,<5 + - libsqlite >=3.45,<4 + run: + - mojo-compiler ${{ mojo_version }} + - ca-certificates >=2025.1.31 + # dodo opens libsqlite3 by name at runtime, so nothing links it. + - libsqlite >=3.45,<4 + +tests: + - requirements: + run: + - mojo ${{ mojo_version }} + - curl + # mojo build links through the system C compiler, which Linux lacks. + - if: linux + then: gcc + files: + recipe: + - tests/package_smoke.mojo + - tests/hello_server.mojo + script: + interpreter: bash + content: + - | + set -euo pipefail + test -f "${PREFIX}/lib/mojo/dodo.mojoc" + for name in tls zlib brotli fs simdjson; do + test -f "${PREFIX}/lib/libdodo_${name}.so" + done + + mojo build tests/package_smoke.mojo -o package_smoke + ./package_smoke + + mojo build tests/hello_server.mojo -o hello_server + ./hello_server 18471 & + SERVER=$! + trap 'kill "${SERVER}" 2>/dev/null || true' EXIT + BODY="" + for attempt in $(seq 1 50); do + if BODY="$(curl -fsS http://127.0.0.1:18471/)"; then + break + fi + sleep 0.2 + done + test "${BODY}" = "hello from dodo" + +about: + homepage: https://github.com/dodo-mojo/dodo + license: Apache-2.0 + license_file: + - LICENSE + - THIRD_PARTY_NOTICES.md + summary: Mojo web framework with AI, GPU and computer vision natively supported, all in one language + repository: https://github.com/dodo-mojo/dodo + +extra: + maintainers: + - anubhav-qt + project_name: dodo diff --git a/recipes/dodo/tests/hello_server.mojo b/recipes/dodo/tests/hello_server.mojo new file mode 100644 index 00000000..7e97197a --- /dev/null +++ b/recipes/dodo/tests/hello_server.mojo @@ -0,0 +1,16 @@ +"""A real server built from the installed package. Usage: hello_server PORT""" + +from std.sys import argv + +from dodo import App, Request, Response, ok + + +def hello(req: Request) raises -> Response: + return ok("hello from dodo") + + +def main() raises: + var app = App() + app.get["/"](hello) + var port = UInt16(Int(argv()[1])) + app.serve(port=port) diff --git a/recipes/dodo/tests/package_smoke.mojo b/recipes/dodo/tests/package_smoke.mojo new file mode 100644 index 00000000..81dd41fc --- /dev/null +++ b/recipes/dodo/tests/package_smoke.mojo @@ -0,0 +1,103 @@ +"""Checks an installed dodo package: the App and every native library. + +Run by the conda recipe's test step against the installed package, not the +source tree. +""" + +from std.testing import assert_equal, assert_true + +from dodo import App, JsonBody, PathParams, Request +from dodo.crypto.digest import sha256 +from dodo.db.sqlite import Sqlite +from dodo.http import Method +from dodo.http.encoding import ( + compress_brotli, + compress_gzip, + decode_content, +) +from dodo.json.ffi.simdjson import simdjson_available + + +@fieldwise_init +struct NamePath(PathParams): + var name: String + + +@fieldwise_init +struct NewUser(JsonBody): + var name: String + var age: Int + + +@fieldwise_init +struct Greeting(Movable): + var message: String + + +@fieldwise_init +struct Created(Movable): + var name: String + var age: Int + + +def hello(req: Request, path: NamePath) raises -> Greeting: + return Greeting(String("hi ", path.name)) + + +def create(req: Request, body: NewUser) raises -> Created: + return Created(body.name, body.age) + + +def check_app() raises: + var app = App() + app.get["/hello/{name}"](hello) + app.post["/users"](create) + + var get_req = Request(method=Method.GET, url="/hello/dodo") + var got = app.serve(get_req) + assert_equal(got.status, 200) + assert_equal(got.text(), '{"message":"hi dodo"}') + + var body = String('{"name":"ada","age":36}') + var post_req = Request( + method=Method.POST, url="/users", body=List[UInt8](body.as_bytes()) + ) + var posted = app.serve(post_req) + assert_equal(posted.status, 200) + assert_equal(posted.text(), '{"name":"ada","age":36}') + + +def check_compression() raises: + var text = String("dodo dodo dodo dodo dodo dodo") + var gzipped = compress_gzip(text.as_bytes()) + var unzipped = decode_content(gzipped, "gzip") + assert_equal(String(unsafe_from_utf8=unzipped), text) + + var brotli = compress_brotli(text.as_bytes()) + var unbrotli = decode_content(brotli, "br") + assert_equal(String(unsafe_from_utf8=unbrotli), text) + + +def check_openssl() raises: + var empty = String("") + var digest = sha256(empty.as_bytes()) + assert_equal(len(digest), 32) + assert_equal(Int(digest[0]), 0xE3) + + +def check_simdjson() raises: + assert_true(simdjson_available(), "libdodo_simdjson.so did not load") + + +def check_sqlite() raises: + var db = Sqlite("sqlite://:memory:") + assert_equal(db.query("select 41 + 1 as n")[0].int("n"), 42) + + +def main() raises: + check_app() + check_compression() + check_openssl() + check_simdjson() + check_sqlite() + print("dodo package smoke test passed")