From 231af23d1c0d21979d95afcaabc724da62e069c5 Mon Sep 17 00:00:00 2001 From: m00d Date: Wed, 1 Oct 2025 12:53:20 +0200 Subject: [PATCH] chore: stage remaining scaffolding --- Makefile.toml | 36 ++++++++ ai/metadata/index.json | 6 +- build.rs | 1 + concepts/nixette/README.md | 91 ++++++++++++++++++++ concepts/nixette/sample_flake.nix | 62 ++++++++++++++ md5sums | 97 +++++++++++++++++++++ src/bin/graphql_server.rs | 80 +++++++++++++++++ src/graphql/context.rs | 138 ++++++++++++++++++++++++++++++ src/graphql/mod.rs | 14 +++ src/graphql/schema.rs | 133 ++++++++++++++++++++++++++++ src/tui/animations/donut.rs | 80 +++++++++++++++++ src/tui/animations/mod.rs | 13 +++ src/tui/animations/progress.rs | 48 +++++++++++ wget-list | 97 +++++++++++++++++++++ 14 files changed, 895 insertions(+), 1 deletion(-) create mode 100644 Makefile.toml create mode 100644 build.rs create mode 100644 concepts/nixette/README.md create mode 100644 concepts/nixette/sample_flake.nix create mode 100644 md5sums create mode 100644 src/bin/graphql_server.rs create mode 100644 src/graphql/context.rs create mode 100644 src/graphql/mod.rs create mode 100644 src/graphql/schema.rs create mode 100644 src/tui/animations/donut.rs create mode 100644 src/tui/animations/mod.rs create mode 100644 src/tui/animations/progress.rs create mode 100644 wget-list diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 0000000..8779f35 --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,36 @@ +[tasks.format] +description = "Format Rust code using rustfmt" +install_crate = "rustfmt" +command = "cargo" +args = ["fmt", "--", "--emit=files"] + +[tasks.clean] +description = "Clean build artifacts" +command = "cargo" +args = ["clean"] + +[tasks.build] +description = "Build the project" +command = "cargo" +args = ["build"] +dependencies = ["clean"] + +[tasks.test] +description = "Run tests" +command = "cargo" +args = ["test"] +dependencies = ["clean"] + +[tasks.my-flow] +description = "Run full workflow: format, build, test" +dependencies = ["format", "build", "test"] + +[tasks.dev-flow] +description = "Full developer workflow: format, lint, build, test" +dependencies = ["format", "clippy", "build", "test"] + +[tasks.release-build] +description = "Build the project in release mode" +command = "cargo" +args = ["build", "--release", "--all-features"] +dependencies = ["clean"] diff --git a/ai/metadata/index.json b/ai/metadata/index.json index 195bf7e..3ff2aa9 100644 --- a/ai/metadata/index.json +++ b/ai/metadata/index.json @@ -1,5 +1,5 @@ { - "generated_at": "2025-10-01T07:30:15.338392+00:00", + "generated_at": "2025-10-01T12:09:20.934066+00:00", "packages": [ { "book": "mlfs", @@ -8,6 +8,7 @@ "path": "packages/mlfs/linux-headers.json", "stage": "cross-toolchain", "status": "draft", + "tags": [], "variant": null, "version": "6.16.9 API Headers" }, @@ -18,6 +19,7 @@ "path": "packages/mlfs/glibc.json", "stage": "cross-toolchain", "status": "draft", + "tags": [], "variant": null, "version": "2.42" }, @@ -28,6 +30,7 @@ "path": "packages/mlfs/binutils-pass-1.json", "stage": "cross-toolchain", "status": "draft", + "tags": [], "variant": "Pass 1", "version": "2.45" }, @@ -38,6 +41,7 @@ "path": "packages/mlfs/gcc-pass-1.json", "stage": "cross-toolchain", "status": "draft", + "tags": [], "variant": "Pass 1", "version": "15.2.0" } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/build.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/concepts/nixette/README.md b/concepts/nixette/README.md new file mode 100644 index 0000000..73c32e6 --- /dev/null +++ b/concepts/nixette/README.md @@ -0,0 +1,91 @@ +# Nixette – Declarative, Sourceful, and Unapologetically Herself + +A playful concept distro imagined as the transfemme child of **NixOS** and **Gentoo**. Nixette blends the reproducible confidence of flakes with the fine-grained self-expression of USE flags, wrapped in a trans flag palette and a big, affirming hug. + +--- + +## Identity Snapshot + +- **Tagline:** _Declarative, sourceful, and unapologetically herself._ +- **Mascot:** Chibi penguin “Nixie” with pastel pigtails, Nix snowflake + Gentoo swirl hoodie. +- **Palette:** `#55CDFC` (sky blue), `#F7A8B8` (pink), `#FFFFFF`, plus a deep accent `#7C3AED`. +- **Pronoun Prompt:** The installer asks for name/pronouns and personalises MOTD, systemd messages, and shell prompt. + +--- + +## Feature Mix + +| Pillar | How Nixette expresses it | +|----------------------|-----------------------------------------------------------------------------------------------------------| +| Reproducibility | Flake-native system definitions with versioned profiles (`comfort-zone`, `diy-princess`, `studio-mode`). | +| Custom compilation | `nix emerge` bridge turns Gentoo ebuild overlays into reproducible derivations with cached binaries. | +| Playful polish | Catppuccin-trans themes, `nixette-style` CLI to sync GTK/Qt/terminal styling, dynamic welcome affirmations.| +| Inclusive defaults | Flatpak + Steam pre-set for accessibility tools, Fcitx5, Orca, speech-dispatcher, pronoun-friendly docs. | + +--- + +## Toolchain Concepts + +- **`trans-init` installer** – Guided TUI that outputs `flake.nix`, including overlays for the `nix emerge` bridge. Provides story-mode narration for first boot. +- **`nixette-style`** – Syncs wallpapers, SDDM theme, terminal palette, Qt/KDE settings, all sourced from a YAML theme pack. +- **`emerge-optional`** – Spins up Gentoo chroots inside Nix build sandboxes for packages happiest as ebuilds. Output is cached as a Nix store derivation. +- **`affirm-d`** – Small daemon rotating `/etc/motd`, desktop notifications, and TTY colour accents with inclusive affirmations. + +--- + +## Profile Catalogue + +| Profile | Intent | +|-----------------|---------------------------------------------------------------------------------------------| +| Comfort Zone | KDE Plasma, PipeWire, Wayland, cozy defaults, automatic Catgirl cursor + emoji fonts. | +| DIY Princess | Minimal sway-based stack, just the flake scaffolding and overlay hooks for custom builds. | +| Studio Mode | Focuses on creative tooling (Krita, Blender, Ardour) and low-latency kernels, GPU tuning. | + +--- + +## Roadmap Sketch + +1. **Moodboard → Brand Pack** (logo, icon, wallpapers, VT boot splash). +2. **Prototype flakes** – `nix flake init --template nixette#comfort-zone` etc. +3. **Gentoo overlay bridge** – Validate `nix emerge` on a handful of ebuilds (mesa, wine, gamescope). +4. **Installer draft** – BubbleTea/ratatui-driven TUI, prompts for pronouns + accessibility preferences. +5. **Community docs** – Write inclusive user guide, contributor covenant, pronoun style guide. +6. **Launch zine** – Release notes styled like a mini-comic introducing Nixie’s origin story. +7. **Accessibility audit** – Keyboard navigation, screen-reader pass, dyslexia-friendly typography options. +8. **Beta cosy jam** – Invite testers via queer sysadmin spaces; collect feedback through anonymous forms. + +--- + +## Affirmations YAML (snippet) + +```yaml +- id: bright-morning + message: "Good morning, {name}! Your system is as valid and custom as you are." + colour: "#F7A8B8" +- id: compile-hugs + message: "Kernel rebuilds take time. You deserve rest breaks and gentle music." + colour: "#55CDFC" +``` + +--- + +## Logo & Wallpaper + +See `assets/nixette-logo.svg` for the primary wordmark, `assets/nixette-mascot.svg` for Nixie’s badge, and `assets/nixette-wallpaper.svg` for a 4K wallpaper concept. + +### Reference Configs + +- `concepts/nixette/sample_flake.nix` demonstrates the comfort-zone profile with `nix emerge`, `affirmd`, and theming hooks. + +--- + +## Contributing Idea Seeds + +- Write sample flakes showcasing the hybrid build pipeline. +- Mock up the mascot in SVG for use in documentation. +- Design additional wallpapers (night mode, pride variants, low-light). +- Draft inclusive documentation templates (issue/PR forms, community guidelines). +- Publish a community pledge emphasising safety, pronoun respect, and boundaries. +- Host monthly "compile & chill" streams to showcase contributions. + +Let Nixette be the distro that compiles joy, not just binaries. 💜 diff --git a/concepts/nixette/sample_flake.nix b/concepts/nixette/sample_flake.nix new file mode 100644 index 0000000..941b524 --- /dev/null +++ b/concepts/nixette/sample_flake.nix @@ -0,0 +1,62 @@ +{ + description = "Nixette comfort-zone profile"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixette-overlays.url = "github:nixette/overlays"; + nixette-style.url = "github:nixette/style-pack"; + }; + + outputs = { self, nixpkgs, nixette-overlays, nixette-style, ... }@inputs: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + overlays = [ nixette-overlays.overlays.nix-emerge ]; + }; + in + { + nixosConfigurations.nixette-comfort-zone = nixpkgs.lib.nixosSystem { + inherit system; + modules = [ + ./profiles/comfort-zone.nix + ({ config, pkgs, ... }: + { + nixpkgs.config.allowUnfree = true; + environment.systemPackages = with pkgs; [ + nixette-style + steam + lutris + krita + ]; + + services.nixette.nix-emerge = { + enable = true; + ebuilds = [ + "games-emulation/gamescope" + "media-sound/pipewire" + ]; + }; + + services.nixette.affirmd.enable = true; + services.nixette.affirmd.pronouns = "she/her"; + services.nixette.affirmd.motdPath = ./affirmations.yml; + + programs.plasma.enable = true; + services.displayManager.sddm.enable = true; + services.displayManager.sddm.theme = nixette-style.themes.catgirl-sunrise; + + users.users.nixie = { + isNormalUser = true; + extraGroups = [ "wheel" "audio" "input" "video" ]; + shell = pkgs.zsh; + }; + + programs.zsh.promptInit = '' + eval "$(nixette-style prompt --name nixie --pronouns she/her)" + ''; + }) + ]; + }; + }; +} diff --git a/md5sums b/md5sums new file mode 100644 index 0000000..44d79f3 --- /dev/null +++ b/md5sums @@ -0,0 +1,97 @@ +590765dee95907dbc3c856f7255bd669 acl-2.3.2.tar.xz +227043ec2f6ca03c0948df5517f9c927 attr-2.5.2.tar.gz +1be79f7106ab6767f18391c5e22be701 autoconf-2.72.tar.xz +cea31dbf1120f890cbf2a3032cfb9a68 automake-1.18.1.tar.xz +977c8c0c5ae6309191e7768e28ebc951 bash-5.3.tar.gz +ad4db5a0eb4fdbb3f6813be4b6b3da74 bc-7.0.3.tar.xz +dee5b4267e0305a99a3c9d6131f45759 binutils-2.45.tar.xz +c28f119f405a2304ff0a7ccdcc629713 bison-3.8.2.tar.xz +67e051268d0c475ea773822f7500d0e5 bzip2-1.0.8.tar.gz +b2e687b6e664b9dd76581836c5c3e782 coreutils-9.8.tar.xz +68c5208c58236eba447d7d6d1326b821 dejagnu-1.6.3.tar.gz +d1b18b20868fb561f77861cd90b05de4 diffutils-3.12.tar.xz +113d7a7ee0710d2a670a44692a35fd2e e2fsprogs-1.47.3.tar.gz +ceefa052ded950a4c523688799193a44 elfutils-0.193.tar.bz2 +423975a2a775ff32f12c53635b463a91 expat-2.7.3.tar.xz +00fce8de158422f5ccd2666512329bd2 expect5.45.4.tar.gz +459da2d4b534801e2e2861611d823864 file-5.46.tar.gz +870cfd71c07d37ebe56f9f4aaf4ad872 findutils-4.10.0.tar.xz +2882e3179748cc9f9c23ec593d6adc8d flex-2.6.4.tar.gz +c538415c1f27bd69cbbbf3cdd5135d39 flit_core-3.12.0.tar.gz +b7014650c5f45e5d4837c31209dc0037 gawk-5.3.2.tar.xz +b861b092bf1af683c46a8aa2e689a6fd gcc-15.2.0.tar.xz +aaa600665bc89e2febb3c7bd90679115 gdbm-1.26.tar.gz +8e14e926f088e292f5f2bce95b81d10e gettext-0.26.tar.xz +23c6f5a27932b435cae94e087cb8b1f5 glibc-2.42.tar.xz +956dc04e864001a9c22429f761f2c283 gmp-6.3.0.tar.xz +31753b021ea78a21f154bf9eecb8b079 gperf-3.3.tar.gz +5d9301ed9d209c4a88c8d3a6fd08b9ac grep-3.12.tar.xz +5e4f40315a22bb8a158748e7d5094c7d groff-1.23.0.tar.gz +60c564b1bdc39d8e43b3aab4bc0fb140 grub-2.12.tar.xz +4bf5a10f287501ee8e8ebe00ef62b2c2 gzip-1.14.tar.xz +437a3e9f4a420244c90db4ab20e713b6 iana-etc-20250926.tar.gz +401d7d07682a193960bcdecafd03de94 inetutils-2.6.tar.xz +12e517cac2b57a0121cda351570f1e63 intltool-0.51.0.tar.gz +80e1f91bf59d572acc15d5c6eb4f3e7c iproute2-6.16.0.tar.xz +11ee9d335b227ea2e8579c4ba6e56138 isl-0.27.tar.xz +66d4c25ff43d1deaf9637ccda523dec8 jinja2-3.1.6.tar.gz +7be7c6f658f5fb9512e2c490349a8eeb kbd-2.9.0.tar.xz +36f2cc483745e81ede3406fa55e1065a kmod-34.2.tar.xz +0386dc14f6a081a94dfb4c2413864eed less-679.tar.gz +2be34eced7c861fea8894e7195dac636 lfs-bootscripts-20250827.tar.xz +449ade7d620b5c4eeb15a632fbaa4f74 libcap-2.76.tar.xz +92af9efad4ba398995abf44835c5d9e9 libffi-3.5.2.tar.gz +17ac6969b2015386bcb5d278a08a40b5 libpipeline-1.5.8.tar.gz +22e0a29df8af5fdde276ea3a7d351d30 libtool-2.5.4.tar.xz +1796a5d20098e9dd9e3f576803c83000 libxcrypt-4.4.38.tar.xz +feb0a3d5ecf5a4628aed7d9f8f7ab3f6 linux-6.16.9.tar.xz +dead9f5f1966d9ae56e1e32761e4e675 lz4-1.10.0.tar.gz +6eb2ebed5b24e74b6e890919331d2132 m4-1.4.20.tar.xz +c8469a3713cbbe04d955d4ae4be23eeb make-4.4.1.tar.gz +b6335533cbeac3b24cd7be31fdee8c83 man-db-2.13.1.tar.xz +16f68d70139dd2bbcae4102be4705753 man-pages-6.15.tar.xz +13a73126d25afa72a1ff0daed072f5fe markupsafe-3.0.3.tar.gz +19e0a1091cec23d369dd77d852844195 meson-1.9.1.tar.gz +5c9bc658c9fd0f940e8e3e0f09530c62 mpc-1.3.1.tar.gz +7c32c39b8b6e3ae85f25156228156061 mpfr-4.2.2.tar.xz +679987405412f970561cc85e1e6428a2 ncurses-6.5-20250809.tgz +c35f8f55f4cf60f1a916068d8f45a0f8 ninja-1.13.1.tar.gz +0ec20faeb96bbb203c8684cc7fe4432e openssl-3.5.3.tar.gz +ab0ef21ddebe09d1803575120d3f99f8 packaging-25.0.tar.gz +149327a021d41c8f88d034eab41c039f patch-2.8.tar.xz +641f99b635ebb9332a9b6a8ce8e2f3cf pcre2-10.46.tar.bz2 +7a6950a9f12d01eb96a9d2ed2f4e0072 perl-5.42.0.tar.xz +3291128c917fdb8fccd8c9e7784b643b pkgconf-2.5.1.tar.xz +90803e64f51f192f3325d25c3335d057 procps-ng-4.0.5.tar.xz +53eae841735189a896d614cba440eb10 psmisc-23.7.tar.xz +256cdb3bbf45cdce7499e52ba6c36ea3 Python-3.13.7.tar.xz +b84c0d81b2758398bb7f5b7411d3d908 python-3.13.7-docs-html.tar.bz2 +25a73bfb2a3ad7146c5e9d4408d9f6cd readline-8.3.tar.gz +6aac9b2dbafcd5b7a67a8a9bcb8036c3 sed-4.9.tar.xz +82e1d67883b713f9493659b50d13b436 setuptools-80.9.0.tar.gz +30ef46f54363db1d624587be68794ef2 shadow-4.18.0.tar.xz +d74bbdca4ab1b2bd46d3b3f8dbb0f3db sqlite-autoconf-3500400.tar.gz +63a62af5b35913459954e6e66876f2b8 sqlite-doc-3500400.tar.xz +af60786956a2dc84054fbf46652e515e sysklogd-2.7.2.tar.gz +25fe5d328e22641254761f1baa74cee0 systemd-257.8.tar.gz +a44063e2ec0cf4adfd2ed5c9e9e095c5 systemd-man-pages-257.8.tar.xz +bc6890b975d19dc9db42d0c7364dd092 sysvinit-3.14.tar.xz +a2d8042658cfd8ea939e6d911eaf4152 tar-1.35.tar.xz +1ec3444533f54d0f86cd120058e15e48 tcl8.6.17-src.tar.gz +60c71044e723b0db5f21be82929f3534 tcl8.6.17-html.tar.gz +11939a7624572814912a18e76c8d8972 texinfo-7.2.tar.xz +ad65154c48c74a9b311fe84778c5434f tzdata2025b.tar.gz +acd4360d8a5c3ef320b9db88d275dae6 udev-lfs-20230818.tar.xz +a2a3281ce76821c4bc28794fdf9d3994 util-linux-2.41.2.tar.xz +e72f31be182f1ccf4b66bef46ac1e60e vim-9.1.1806.tar.gz +65e09ee84af36821e3b1e9564aa91bd5 wheel-0.46.1.tar.gz +89a8e82cfd2ad948b349c0a69c494463 XML-Parser-2.47.tar.gz +cf5e1feb023d22c6bdaa30e84ef3abe3 xz-5.8.1.tar.xz +9855b6d802d7fe5b7bd5b196a2271655 zlib-1.3.1.tar.gz +780fc1896922b1bc52a4e90980cdda48 zstd-1.5.7.tar.gz +6a5ac7e89b791aae556de0f745916f7f bzip2-1.0.8-install_docs-1.patch +c800540039fb0707954197486b1bde70 coreutils-9.8-i18n-2.patch +0ca4d6bb8d572fbcdb13cb36cd34833e expect-5.45.4-gcc15-1.patch +9a5997c3452909b1769918c759eff8a2 glibc-2.42-fhs-1.patch +f75cca16a38da6caa7d52151f7136895 kbd-2.9.0-backspace-1.patch +3af8fd8e13cad481eeeaa48be4247445 sysvinit-3.14-consolidated-1.patch diff --git a/src/bin/graphql_server.rs b/src/bin/graphql_server.rs new file mode 100644 index 0000000..5fee14a --- /dev/null +++ b/src/bin/graphql_server.rs @@ -0,0 +1,80 @@ +#![cfg(feature = "graphql")] + +use std::env; +use std::sync::Arc; + +use actix_web::{App, HttpRequest, HttpResponse, HttpServer, middleware::Compress, web}; +use anyhow::{Context, Result}; +use juniper_actix::{graphiql_handler, graphql_handler}; + +use package_management::db; +use package_management::graphql::{self, GraphQLContext, Schema}; + +const DEFAULT_BIND_ADDR: &str = "127.0.0.1:8080"; + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + if let Err(err) = run().await { + eprintln!("GraphQL server failed: {err:#}"); + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + err.to_string(), + )); + } + + Ok(()) +} + +async fn run() -> Result<()> { + let pool = db::establish_pool().context("initialising SQLite pool")?; + let schema = Arc::new(graphql::create_schema()); + let jokes = Arc::new(graphql::context::JokeCatalog::default()); + let bind_addr = env::var("LPKG_GRAPHQL_ADDR").unwrap_or_else(|_| DEFAULT_BIND_ADDR.to_string()); + let workers = worker_count(); + + println!("GraphQL server listening on {bind_addr} with {workers} worker(s)"); + + HttpServer::new(move || { + let app_schema = Arc::clone(&schema); + let pool = pool.clone(); + let jokes = Arc::clone(&jokes); + + App::new() + .app_data(web::Data::from(app_schema)) + .app_data(web::Data::new(pool)) + .app_data(web::Data::from(jokes)) + .wrap(Compress::default()) + .service( + web::resource("/graphql") + .route(web::post().to(graphql_endpoint)) + .route(web::get().to(graphql_endpoint)), + ) + .service(web::resource("/playground").route(web::get().to(graphiql_endpoint))) + }) + .workers(workers) + .bind(&bind_addr) + .with_context(|| format!("binding GraphQL server to {bind_addr}"))? + .run() + .await + .context("running GraphQL server") +} + +async fn graphql_endpoint( + schema: web::Data>, + pool: web::Data, + jokes: web::Data>, + req: HttpRequest, + payload: web::Payload, +) -> Result { + let context = GraphQLContext::with_catalog(pool.get_ref().clone(), Arc::clone(jokes.get_ref())); + graphql_handler(schema.get_ref().as_ref(), &context, req, payload).await +} + +async fn graphiql_endpoint() -> Result { + graphiql_handler("/graphql", None).await +} + +fn worker_count() -> usize { + let suggested = num_cpus::get(); + suggested.clamp(1, 8) +} diff --git a/src/graphql/context.rs b/src/graphql/context.rs new file mode 100644 index 0000000..a37e4de --- /dev/null +++ b/src/graphql/context.rs @@ -0,0 +1,138 @@ +use std::sync::Arc; + +use rand::rng; +use rand::seq::IteratorRandom; + +use crate::db; + +#[derive(Clone)] +pub struct GraphQLContext { + pub db_pool: db::Pool, + jokes: Arc, +} + +impl GraphQLContext { + pub fn new(db_pool: db::Pool) -> Self { + Self { + db_pool, + jokes: Arc::new(JokeCatalog::default()), + } + } + + pub fn with_jokes(db_pool: db::Pool, jokes: Vec) -> Self { + Self { + db_pool, + jokes: Arc::new(JokeCatalog::new(jokes)), + } + } + + pub fn with_catalog(db_pool: db::Pool, catalog: Arc) -> Self { + Self { + db_pool, + jokes: catalog, + } + } + + pub fn joke_catalog(&self) -> Arc { + Arc::clone(&self.jokes) + } +} + +impl juniper::Context for GraphQLContext {} + +#[derive(Clone, Debug)] +pub struct Joke { + pub id: String, + pub package: Option, + pub text: String, +} + +impl Joke { + pub fn new(id: impl Into, package: Option<&str>, text: impl Into) -> Self { + Self { + id: id.into(), + package: package.map(|pkg| pkg.to_string()), + text: text.into(), + } + } +} + +#[derive(Clone)] +pub struct JokeCatalog { + entries: Arc>, +} + +impl JokeCatalog { + fn new(entries: Vec) -> Self { + Self { + entries: Arc::new(entries), + } + } + + pub fn random(&self, package: Option<&str>) -> Option { + let mut rng = rng(); + + if let Some(package) = package { + if let Some(chosen) = self + .entries + .iter() + .filter(|joke| matches_package(joke, package)) + .choose(&mut rng) + { + return Some(chosen.clone()); + } + } + + self.entries.iter().choose(&mut rng).cloned() + } + + pub fn all(&self, package: Option<&str>) -> Vec { + match package { + Some(package) => self + .entries + .iter() + .filter(|joke| matches_package(joke, package)) + .cloned() + .collect(), + None => self.entries.as_ref().clone(), + } + } +} + +impl Default for JokeCatalog { + fn default() -> Self { + Self::new(default_jokes()) + } +} + +fn matches_package(joke: &Joke, package: &str) -> bool { + joke.package + .as_deref() + .map(|pkg| pkg.eq_ignore_ascii_case(package)) + .unwrap_or(false) +} + +fn default_jokes() -> Vec { + vec![ + Joke::new( + "optimizer-overdrive", + Some("gcc"), + "The GCC optimizer walked into a bar, reordered everyone’s drinks, and they still tasted the same—just faster.", + ), + Joke::new( + "linker-chuckle", + Some("binutils"), + "Our linker refuses to go on vacation; it can’t handle unresolved references to the beach.", + ), + Joke::new( + "glibc-giggle", + Some("glibc"), + "The C library tried stand-up comedy but segfaulted halfway through the punchline.", + ), + Joke::new( + "pkg-general", + None, + "LPKG packages never get lost—they always follow the dependency graph back home.", + ), + ] +} diff --git a/src/graphql/mod.rs b/src/graphql/mod.rs new file mode 100644 index 0000000..9c8a0b3 --- /dev/null +++ b/src/graphql/mod.rs @@ -0,0 +1,14 @@ +pub mod context; +pub mod schema; + +pub use context::{GraphQLContext, Joke}; +pub use schema::QueryRoot; + +use juniper::{EmptyMutation, EmptySubscription, RootNode}; + +pub type Schema = + RootNode, EmptySubscription>; + +pub fn create_schema() -> Schema { + Schema::new(QueryRoot {}, EmptyMutation::new(), EmptySubscription::new()) +} diff --git a/src/graphql/schema.rs b/src/graphql/schema.rs new file mode 100644 index 0000000..d27d855 --- /dev/null +++ b/src/graphql/schema.rs @@ -0,0 +1,133 @@ +use anyhow::{Error as AnyhowError, Result as AnyhowResult}; +use juniper::{FieldResult, GraphQLObject, Value, graphql_object}; + +use crate::{db, pkgs::package::PackageDefinition}; + +use super::context::{GraphQLContext, Joke}; + +#[derive(Clone, GraphQLObject)] +#[graphql(description = "Package metadata exposed via the GraphQL API")] +pub struct PackageType { + pub name: String, + pub version: String, + pub source: Option, + pub md5: Option, + pub configure_args: Vec, + pub build_commands: Vec, + pub install_commands: Vec, + pub dependencies: Vec, + pub enable_lto: bool, + pub enable_pgo: bool, + pub cflags: Vec, + pub ldflags: Vec, + pub profdata: Option, +} + +impl From for PackageType { + fn from(pkg: PackageDefinition) -> Self { + let optimizations = pkg.optimizations; + + Self { + name: pkg.name, + version: pkg.version, + source: pkg.source, + md5: pkg.md5, + configure_args: pkg.configure_args, + build_commands: pkg.build_commands, + install_commands: pkg.install_commands, + dependencies: pkg.dependencies, + enable_lto: optimizations.enable_lto, + enable_pgo: optimizations.enable_pgo, + cflags: optimizations.cflags, + ldflags: optimizations.ldflags, + profdata: optimizations.profdata, + } + } +} + +#[derive(Clone, GraphQLObject)] +#[graphql(description = "A light-hearted package-related joke")] +pub struct JokeType { + pub id: String, + pub package: Option, + pub text: String, +} + +impl From for JokeType { + fn from(joke: Joke) -> Self { + Self { + id: joke.id, + package: joke.package, + text: joke.text, + } + } +} + +#[derive(Default)] +pub struct QueryRoot; + +#[graphql_object(context = GraphQLContext)] +impl QueryRoot { + fn packages(context: &GraphQLContext, limit: Option) -> FieldResult> { + let limit = limit.unwrap_or(50).clamp(1, 200) as usize; + let definitions = + db::load_package_definitions_via_pool(&context.db_pool).map_err(field_error)?; + + Ok(definitions + .into_iter() + .take(limit) + .map(PackageType::from) + .collect()) + } + + fn package( + context: &GraphQLContext, + name: String, + version: Option, + ) -> FieldResult> { + let definition = + db::find_package_definition_via_pool(&context.db_pool, &name, version.as_deref()) + .map_err(field_error)?; + + Ok(definition.map(PackageType::from)) + } + + fn search( + context: &GraphQLContext, + query: String, + limit: Option, + ) -> FieldResult> { + let limit = limit.map(|value| i64::from(value.clamp(1, 200))); + let results = + db::search_packages_via_pool(&context.db_pool, &query, limit).map_err(field_error)?; + + let packages = results + .into_iter() + .map(|pkg| pkg.into_definition().map(PackageType::from)) + .collect::>>() + .map_err(field_error)?; + + Ok(packages) + } + + fn jokes(context: &GraphQLContext, package: Option) -> FieldResult> { + let catalog = context.joke_catalog(); + Ok(catalog + .all(package.as_deref()) + .into_iter() + .map(JokeType::from) + .collect()) + } + + fn random_joke( + context: &GraphQLContext, + package: Option, + ) -> FieldResult> { + let catalog = context.joke_catalog(); + Ok(catalog.random(package.as_deref()).map(JokeType::from)) + } +} + +fn field_error(err: AnyhowError) -> juniper::FieldError { + juniper::FieldError::new(err.to_string(), Value::null()) +} diff --git a/src/tui/animations/donut.rs b/src/tui/animations/donut.rs new file mode 100644 index 0000000..531c4f3 --- /dev/null +++ b/src/tui/animations/donut.rs @@ -0,0 +1,80 @@ +use std::time::Duration; +use rsille::canvas::Canvas; +use super::Animation; + +const THETA_SPACING: f64 = 0.07; +const PHI_SPACING: f64 = 0.02; + +pub struct DonutAnimation { + a: f64, // rotation around X + b: f64, // rotation around Z + size: (u16, u16), +} + +impl DonutAnimation { + pub fn new(width: u16, height: u16) -> Self { + Self { + a: 0.0, + b: 0.0, + size: (width, height), + } + } +} + +impl Animation for DonutAnimation { + fn update(&mut self, delta: Duration) { + let delta_secs = delta.as_secs_f64(); + self.a += delta_secs; + self.b += delta_secs * 0.5; + } + + fn render(&self, canvas: &mut Canvas) { + let (width, height) = self.size; + let (width_f, height_f) = (width as f64, height as f64); + let k2 = 5.0; + let k1 = width_f * k2 * 3.0 / (8.0 * (height_f + width_f)); + + for theta in 0..((2.0 * std::f64::consts::PI / THETA_SPACING) as i32) { + let theta_f = theta as f64 * THETA_SPACING; + let cos_theta = theta_f.cos(); + let sin_theta = theta_f.sin(); + + for phi in 0..((2.0 * std::f64::consts::PI / PHI_SPACING) as i32) { + let phi_f = phi as f64 * PHI_SPACING; + let cos_phi = phi_f.cos(); + let sin_phi = phi_f.sin(); + + let cos_a = self.a.cos(); + let sin_a = self.a.sin(); + let cos_b = self.b.cos(); + let sin_b = self.b.sin(); + + let h = cos_theta + 2.0; + let d = 1.0 / (sin_phi * h * sin_a + sin_theta * cos_a + 5.0); + let t = sin_phi * h * cos_a - sin_theta * sin_a; + + let x = (width_f / 2.0 + 30.0 * d * (cos_phi * h * cos_b - t * sin_b)) as i32; + let y = (height_f / 2.0 + 15.0 * d * (cos_phi * h * sin_b + t * cos_b)) as i32; + let z = (1.0 / d) as u8; + + if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 { + let luminance = if z > 0 { z } else { 1 }; + let c = match luminance { + 0..=31 => '.', + 32..=63 => '*', + 64..=95 => 'o', + 96..=127 => '&', + 128..=159 => '8', + 160..=191 => '#', + _ => '@', + }; + canvas.put_char(x as u16, y as u16, c); + } + } + } + } + + fn is_finished(&self) -> bool { + false // continuous animation + } +} \ No newline at end of file diff --git a/src/tui/animations/mod.rs b/src/tui/animations/mod.rs new file mode 100644 index 0000000..5eb3a7b --- /dev/null +++ b/src/tui/animations/mod.rs @@ -0,0 +1,13 @@ +use rsille::canvas::Canvas; +use std::time::Duration; + +pub trait Animation { + fn update(&mut self, delta: Duration); + fn render(&self, canvas: &mut Canvas); + fn is_finished(&self) -> bool; +} + +pub trait ProgressAnimation: Animation { + fn set_progress(&mut self, progress: f64); + fn get_progress(&self) -> f64; +} diff --git a/src/tui/animations/progress.rs b/src/tui/animations/progress.rs new file mode 100644 index 0000000..5ac2377 --- /dev/null +++ b/src/tui/animations/progress.rs @@ -0,0 +1,48 @@ +use std::time::Duration; +use rsille::canvas::Canvas; +use super::{Animation, ProgressAnimation}; + +pub struct ProgressBarAnimation { + progress: f64, + width: u16, + height: u16, + animation_offset: f64, +} + +impl ProgressBarAnimation { + pub fn new(width: u16, height: u16) -> Self { + Self { + progress: 0.0, + width, + height, + animation_offset: 0.0, + } + } +} + +impl Animation for ProgressBarAnimation { + fn update(&mut self, delta: Duration) { + self.animation_offset += delta.as_secs_f64() * 2.0; + if self.animation_offset >= 1.0 { + self.animation_offset -= 1.0; + } + } + + fn render(&self, canvas: &mut Canvas) { + // Animated progress bar rendering will be implemented here + } + + fn is_finished(&self) -> bool { + self.progress >= 1.0 + } +} + +impl ProgressAnimation for ProgressBarAnimation { + fn set_progress(&mut self, progress: f64) { + self.progress = progress.clamp(0.0, 1.0); + } + + fn get_progress(&self) -> f64 { + self.progress + } +} \ No newline at end of file diff --git a/wget-list b/wget-list new file mode 100644 index 0000000..127aa84 --- /dev/null +++ b/wget-list @@ -0,0 +1,97 @@ +https://download.savannah.gnu.org/releases/acl/acl-2.3.2.tar.xz +https://download.savannah.gnu.org/releases/attr/attr-2.5.2.tar.gz +https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz +https://ftp.gnu.org/gnu/automake/automake-1.18.1.tar.xz +https://ftp.gnu.org/gnu/bash/bash-5.3.tar.gz +https://github.com/gavinhoward/bc/releases/download/7.0.3/bc-7.0.3.tar.xz +https://sourceware.org/pub/binutils/releases/binutils-2.45.tar.xz +https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.xz +https://www.sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz +https://ftp.gnu.org/gnu/coreutils/coreutils-9.8.tar.xz +https://ftp.gnu.org/gnu/dejagnu/dejagnu-1.6.3.tar.gz +https://ftp.gnu.org/gnu/diffutils/diffutils-3.12.tar.xz +https://downloads.sourceforge.net/project/e2fsprogs/e2fsprogs/v1.47.3/e2fsprogs-1.47.3.tar.gz +https://sourceware.org/ftp/elfutils/0.193/elfutils-0.193.tar.bz2 +https://github.com/libexpat/libexpat/releases/download/R_2_7_3/expat-2.7.3.tar.xz +https://prdownloads.sourceforge.net/expect/expect5.45.4.tar.gz +https://astron.com/pub/file/file-5.46.tar.gz +https://ftp.gnu.org/gnu/findutils/findutils-4.10.0.tar.xz +https://github.com/westes/flex/releases/download/v2.6.4/flex-2.6.4.tar.gz +https://pypi.org/packages/source/f/flit-core/flit_core-3.12.0.tar.gz +https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz +https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz +https://ftp.gnu.org/gnu/gdbm/gdbm-1.26.tar.gz +https://ftp.gnu.org/gnu/gettext/gettext-0.26.tar.xz +https://ftp.gnu.org/gnu/glibc/glibc-2.42.tar.xz +https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz +https://ftp.gnu.org/gnu/gperf/gperf-3.3.tar.gz +https://ftp.gnu.org/gnu/grep/grep-3.12.tar.xz +https://ftp.gnu.org/gnu/groff/groff-1.23.0.tar.gz +https://ftp.gnu.org/gnu/grub/grub-2.12.tar.xz +https://ftp.gnu.org/gnu/gzip/gzip-1.14.tar.xz +https://github.com/Mic92/iana-etc/releases/download/20250926/iana-etc-20250926.tar.gz +https://ftp.gnu.org/gnu/inetutils/inetutils-2.6.tar.xz +https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz +https://www.kernel.org/pub/linux/utils/net/iproute2/iproute2-6.16.0.tar.xz +https://libisl.sourceforge.io/isl-0.27.tar.xz +https://pypi.org/packages/source/J/Jinja2/jinja2-3.1.6.tar.gz +https://www.kernel.org/pub/linux/utils/kbd/kbd-2.9.0.tar.xz +https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-34.2.tar.xz +https://www.greenwoodsoftware.com/less/less-679.tar.gz +https://www.linuxfromscratch.org/lfs/downloads/development/lfs-bootscripts-20250827.tar.xz +https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-2.76.tar.xz +https://github.com/libffi/libffi/releases/download/v3.5.2/libffi-3.5.2.tar.gz +https://download.savannah.gnu.org/releases/libpipeline/libpipeline-1.5.8.tar.gz +https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.xz +https://github.com/besser82/libxcrypt/releases/download/v4.4.38/libxcrypt-4.4.38.tar.xz +https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.16.9.tar.xz +https://github.com/lz4/lz4/releases/download/v1.10.0/lz4-1.10.0.tar.gz +https://ftp.gnu.org/gnu/m4/m4-1.4.20.tar.xz +https://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz +https://download.savannah.gnu.org/releases/man-db/man-db-2.13.1.tar.xz +https://www.kernel.org/pub/linux/docs/man-pages/man-pages-6.15.tar.xz +https://pypi.org/packages/source/M/MarkupSafe/markupsafe-3.0.3.tar.gz +https://github.com/mesonbuild/meson/releases/download/1.9.1/meson-1.9.1.tar.gz +https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz +https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.2.tar.xz +https://invisible-mirror.net/archives/ncurses/current/ncurses-6.5-20250809.tgz +https://github.com/ninja-build/ninja/archive/v1.13.1/ninja-1.13.1.tar.gz +https://github.com/openssl/openssl/releases/download/openssl-3.5.3/openssl-3.5.3.tar.gz +https://files.pythonhosted.org/packages/source/p/packaging/packaging-25.0.tar.gz +https://ftp.gnu.org/gnu/patch/patch-2.8.tar.xz +https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.46/pcre2-10.46.tar.bz2 +https://www.cpan.org/src/5.0/perl-5.42.0.tar.xz +https://distfiles.ariadne.space/pkgconf/pkgconf-2.5.1.tar.xz +https://sourceforge.net/projects/procps-ng/files/Production/procps-ng-4.0.5.tar.xz +https://sourceforge.net/projects/psmisc/files/psmisc/psmisc-23.7.tar.xz +https://www.python.org/ftp/python/3.13.7/Python-3.13.7.tar.xz +https://www.python.org/ftp/python/doc/3.13.7/python-3.13.7-docs-html.tar.bz2 +https://ftp.gnu.org/gnu/readline/readline-8.3.tar.gz +https://ftp.gnu.org/gnu/sed/sed-4.9.tar.xz +https://pypi.org/packages/source/s/setuptools/setuptools-80.9.0.tar.gz +https://github.com/shadow-maint/shadow/releases/download/4.18.0/shadow-4.18.0.tar.xz +https://sqlite.org/2025/sqlite-autoconf-3500400.tar.gz +https://anduin.linuxfromscratch.org/LFS/sqlite-doc-3500400.tar.xz +https://github.com/troglobit/sysklogd/releases/download/v2.7.2/sysklogd-2.7.2.tar.gz +https://github.com/systemd/systemd/archive/v257.8/systemd-257.8.tar.gz +https://anduin.linuxfromscratch.org/LFS/systemd-man-pages-257.8.tar.xz +https://github.com/slicer69/sysvinit/releases/download/3.14/sysvinit-3.14.tar.xz +https://ftp.gnu.org/gnu/tar/tar-1.35.tar.xz +https://downloads.sourceforge.net/tcl/tcl8.6.17-src.tar.gz +https://downloads.sourceforge.net/tcl/tcl8.6.17-html.tar.gz +https://ftp.gnu.org/gnu/texinfo/texinfo-7.2.tar.xz +https://www.iana.org/time-zones/repository/releases/tzdata2025b.tar.gz +https://anduin.linuxfromscratch.org/LFS/udev-lfs-20230818.tar.xz +https://www.kernel.org/pub/linux/utils/util-linux/v2.41/util-linux-2.41.2.tar.xz +https://github.com/vim/vim/archive/v9.1.1806/vim-9.1.1806.tar.gz +https://pypi.org/packages/source/w/wheel/wheel-0.46.1.tar.gz +https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-2.47.tar.gz +https://github.com//tukaani-project/xz/releases/download/v5.8.1/xz-5.8.1.tar.xz +https://zlib.net/fossils/zlib-1.3.1.tar.gz +https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz +https://www.linuxfromscratch.org/patches/lfs/development/bzip2-1.0.8-install_docs-1.patch +https://www.linuxfromscratch.org/patches/lfs/development/coreutils-9.8-i18n-2.patch +https://www.linuxfromscratch.org/patches/lfs/development/expect-5.45.4-gcc15-1.patch +https://www.linuxfromscratch.org/patches/lfs/development/glibc-2.42-fhs-1.patch +https://www.linuxfromscratch.org/patches/lfs/development/kbd-2.9.0-backspace-1.patch +https://www.linuxfromscratch.org/patches/lfs/development/sysvinit-3.14-consolidated-1.patch