diff --git a/.github/builtin/index.json b/.github/builtin/index.json new file mode 100644 index 0000000..a49024e --- /dev/null +++ b/.github/builtin/index.json @@ -0,0 +1,46 @@ +{ + "services": [ + { + "name": "mysql", + "description": "MySQL database", + "category": "databases", + "icon": "database", + "color": "#4479a1" + }, + { + "name": "postgres", + "description": "PostgreSQL with PostGIS", + "category": "databases", + "icon": "elephant", + "color": "#4169e1" + }, + { + "name": "redis", + "description": "Redis in-memory store", + "category": "cache", + "icon": "bolt", + "color": "#ff4438" + }, + { + "name": "meilisearch", + "description": "Meilisearch search engine", + "category": "search", + "icon": "search", + "color": "#ff5caa" + }, + { + "name": "rustfs", + "description": "RustFS S3-compatible object storage", + "category": "storage", + "icon": "storage", + "color": "#0196d0" + }, + { + "name": "mailpit", + "description": "Mailpit SMTP catcher", + "category": "mail", + "icon": "mail", + "color": "#00b786" + } + ] +} diff --git a/.github/builtin/mailpit.svg b/.github/builtin/mailpit.svg new file mode 100644 index 0000000..bcf1b7a --- /dev/null +++ b/.github/builtin/mailpit.svg @@ -0,0 +1 @@ + diff --git a/.github/builtin/meilisearch.svg b/.github/builtin/meilisearch.svg new file mode 100644 index 0000000..a8d0bc1 --- /dev/null +++ b/.github/builtin/meilisearch.svg @@ -0,0 +1 @@ + diff --git a/.github/builtin/mysql.svg b/.github/builtin/mysql.svg new file mode 100644 index 0000000..1ef827e --- /dev/null +++ b/.github/builtin/mysql.svg @@ -0,0 +1 @@ + diff --git a/.github/builtin/postgres.svg b/.github/builtin/postgres.svg new file mode 100644 index 0000000..5224da0 --- /dev/null +++ b/.github/builtin/postgres.svg @@ -0,0 +1 @@ + diff --git a/.github/builtin/redis.svg b/.github/builtin/redis.svg new file mode 100644 index 0000000..d375892 --- /dev/null +++ b/.github/builtin/redis.svg @@ -0,0 +1 @@ + diff --git a/.github/glyphs/storage.svg b/.github/glyphs/storage.svg new file mode 100644 index 0000000..4ffaaa5 --- /dev/null +++ b/.github/glyphs/storage.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/mailpit.svg b/.github/logos/mailpit.svg new file mode 100644 index 0000000..e9b70be --- /dev/null +++ b/.github/logos/mailpit.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/meilisearch.svg b/.github/logos/meilisearch.svg new file mode 100644 index 0000000..5432ef1 --- /dev/null +++ b/.github/logos/meilisearch.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/mysql.svg b/.github/logos/mysql.svg new file mode 100644 index 0000000..7fbed13 --- /dev/null +++ b/.github/logos/mysql.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/postgres.svg b/.github/logos/postgres.svg new file mode 100644 index 0000000..9e24063 --- /dev/null +++ b/.github/logos/postgres.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/redis.svg b/.github/logos/redis.svg new file mode 100644 index 0000000..4534e66 --- /dev/null +++ b/.github/logos/redis.svg @@ -0,0 +1 @@ + diff --git a/.github/logos/rustfs.svg b/.github/logos/rustfs.svg new file mode 100644 index 0000000..bbd21ad --- /dev/null +++ b/.github/logos/rustfs.svg @@ -0,0 +1 @@ + diff --git a/.github/scripts/readme_logos.py b/.github/scripts/readme_logos.py index b486825..96f4664 100644 --- a/.github/scripts/readme_logos.py +++ b/.github/scripts/readme_logos.py @@ -16,6 +16,7 @@ import sys ROOT = pathlib.Path(__file__).resolve().parents[2] +BUILTIN = ROOT / ".github" / "builtin" GLYPHS = ROOT / ".github" / "glyphs" OUT = ROOT / ".github" / "logos" @@ -47,9 +48,12 @@ def split(svg: str, source: str) -> tuple[str, str]: def services() -> list[dict]: # Newer schemas list presets older binaries cannot read, so the README - # takes every index there is and lets a later one win a name. + # takes every index there is and lets a later one win a name. The default + # stack ships inside lerd rather than here, and .github/builtin mirrors it + # so the README can list MySQL and friends beside everything else. merged = {} - for index in [ROOT / "services" / "index.json", *sorted(ROOT.glob("schema/*/services/index.json"))]: + indexes = [BUILTIN / "index.json", ROOT / "services" / "index.json", *sorted(ROOT.glob("schema/*/services/index.json"))] + for index in indexes: for entry in json.loads(index.read_text())["services"]: merged[entry["name"]] = entry return list(merged.values()) @@ -58,6 +62,8 @@ def services() -> list[dict]: def render(entry: dict) -> str: name = entry["name"] mark = ROOT / "services" / f"{name}.svg" + if not mark.exists(): + mark = BUILTIN / f"{name}.svg" if mark.exists(): viewbox, body = split(mark.read_text(), mark.name) return TILE.format(inset=13, size=38, viewbox=viewbox, attrs=f' fill="{entry["color"]}"', body=body) diff --git a/README.md b/README.md index affe2fa..7e4ad46 100644 --- a/README.md +++ b/README.md @@ -12,22 +12,26 @@

- adminer - clickhouse - elasticsearch - kafka - localstack - mariadb - mercure - mongo - opensearch - phpmyadmin - PostgreSQL - rabbitmq - selenium - solr - stripe-mock - valkey + adminer + clickhouse + elasticsearch + kafka + localstack + mailpit + mariadb + meilisearch + mercure + mongo + mysql + opensearch + phpmyadmin + postgres + rabbitmq + redis + selenium + solr + stripe-mock + valkey

Run `lerd service search`, pick something, `lerd service preset ` — and Lerd pulls the matching preset from this store, then knows exactly how to run it: which image and ports, how to wire your project's `.env`, which admin dashboard to embed, what it depends on, and which config files to mount for auto-login. Everything is a single YAML file. Add a service here and every Lerd install can use it within 24 hours, with no new Lerd release and no Go code. @@ -57,6 +61,8 @@ All of it is data. None of it ships in the binary. | | `clickhouse` | ClickHouse column-oriented analytics database, with its own SQL console | | | `mariadb` | MariaDB, the MySQL-compatible server (multi-version) | | | `mongo` | MongoDB document database | +| | `mysql` | MySQL database server · **built into Lerd** | +| | `postgres` | PostgreSQL with PostGIS · **built into Lerd** | | | `postgres-pgvector` | PostgreSQL + pgvector for vector search (multi-version) | | | `postgres-timescaledb` | PostgreSQL + TimescaleDB for time-series (multi-version) | @@ -79,6 +85,7 @@ All of it is data. None of it ships in the binary. | | Service | What it is | |:-:|---|---| | | `elasticsearch` | Elasticsearch single-node engine | +| | `meilisearch` | Meilisearch search engine · **built into Lerd** | | | `opensearch` | OpenSearch single-node engine | | | `solr` | Apache Solr, the search backend Drupal and TYPO3 expect | | | `typesense` | Typesense typo-tolerant search | @@ -92,6 +99,7 @@ All of it is data. None of it ships in the binary. | | `memcached` | Memcached in-memory cache | | | `mercure` | Mercure hub for server-sent events, the Symfony realtime transport | | | `rabbitmq` | RabbitMQ broker with management UI | +| | `redis` | Redis in-memory store · **built into Lerd** | | | `soketi` | Pusher-compatible WebSocket server | | | `valkey` | Valkey, the Redis-compatible cache (coexists with Redis) | @@ -101,6 +109,8 @@ All of it is data. None of it ships in the binary. |:-:|---|---| | | `gotenberg` | Gotenberg API for PDF and document conversion | | | `localstack` | LocalStack, the AWS APIs run locally (SQS, SES, DynamoDB, Secrets Manager) | +| | `mailpit` | Mailpit SMTP catcher with a web inbox · **built into Lerd** | +| | `rustfs` | RustFS S3-compatible object storage · **built into Lerd** | | | `selenium` | Headless Chromium with a noVNC viewer for browser tests | | | `spamassassin` | SpamAssassin scoring backend for the Mailpit catcher | | | `stripe-mock` | Stripe API mock server | @@ -232,7 +242,7 @@ A family is the other way round. Every member of one is that engine, so they all carry its mark and its colour: pgvector and TimescaleDB are Postgres, and both draw the Postgres elephant in Postgres blue rather than a mark of their own. -The coloured tiles in this README are not the marks themselves. `.github/scripts/readme_logos.py` paints each mark in its declared colour on a white tile, so GitHub shows it in either theme, and a service without one gets the lerd glyph its `icon` names in its category's tint, from copies kept in `.github/glyphs/`. It writes the result to `.github/logos/`; run it again whenever a service, its mark or its colour changes. +The coloured tiles in this README are not the marks themselves. `.github/scripts/readme_logos.py` paints each mark in its declared colour on a white tile, so GitHub shows it in either theme, and a service without one gets the lerd glyph its `icon` names in its category's tint, from copies kept in `.github/glyphs/`. The six services built into lerd are listed too, from the marks and colours mirrored in `.github/builtin/`. It writes the result to `.github/logos/`; run it again whenever a service, its mark or its colour changes. See the [service presets documentation](https://lerd.sh/usage/service-presets) for the full schema reference and every available field.