···11# Unsurprising
2233+As of today, this repository is exclusively to play around and think about a toy language with a goal close to Nix.
44+55+# Parts
66+77+## Examples
88+99+Examples are split into different use-cases. You can check the files in `examples`.
1010+1111+- `core`: contains definitions of builtins
1212+1313+- `cur`: cristal user repository
1414+1515+- `machine`: contains a crystal (flake) definition for a machine definition
1616+1717+- `project`: contains a crystal (flake) definition for a project
1818+319# Lecture
42055-- The Purely Functional Software Deployment Model
2121+- The Purely Functional Software Deployment Model — Eelco Dolstra
622- https://jonathanlorimer.dev/posts/nix-thesis.html
+104
examples/core/lib.rs
···11+// # Ressources
22+// https://github.com/NixOS/nixpkgs/blob/master/doc/stdenv/stdenv.chapter.md
33+// ---
44+55+//! In separate crates/projects
66+77+/// tools for transforming data, building derivations
88+mod core {
99+ // lib, build, install, etc.
1010+1111+ // equivalent for flake
1212+ mod cristal {
1313+1414+ }
1515+1616+ mod derivation {
1717+ struct Drv<I, O> {
1818+ pub meta: DrvMeta,
1919+ pub source: Source,
2020+ pub plan: BuildPlan,
2121+2222+ // this can be overridden when building
2323+ inputs: I,
2424+2525+ // this can be accessed after building
2626+ outputs: O,
2727+ }
2828+2929+ impl Drv<I, O> {
3030+ fn build(self, patch_inputs: Partial<I>) -> Result<O> {
3131+ // path the default inputs with custom ones
3232+ let current_inputs = self.inputs.override(patch_inputs);
3333+3434+ // <large snip>
3535+ // execute build plan with
3636+ }
3737+ }
3838+3939+ let _ = || {
4040+ let whatever_drv: Drv<I, O> = Drv::new /* ... */;
4141+ let whatever: O = pkgs::whatever_drv.build {};
4242+4343+ // whatever is
4444+ {
4545+ bin: {
4646+ path: "store:<hash>-whatever-0.0.0-bin",
4747+ // join pathes
4848+ whatever: "store:<hash>-whatever-0.0.0-bin" + "whatever",
4949+ },
5050+ man: {
5151+ path: "store:<hash>-whatever-0.0.0-man",
5252+ },
5353+ }
5454+5555+ let my_bin = make_new_script {
5656+ name: "hello",
5757+ script: || {
5858+ let res = Command::new(whatever.bin.whatever).exec();
5959+6060+ println(res);
6161+ },
6262+ };
6363+6464+ let screenshot_bin = std::make_script("lock-screenshot.sh", || {
6565+ let tmp_img = Cmd::new(coreutils.bin.mktemp).arg("/tmp/lock-bg.XXX").exec()?;
6666+6767+ // Give some time to hide the bar
6868+ std::sleep_milis(1);
6969+7070+ Cmd::new(grim.bin.grim).arg(tmp_img).exec()?;
7171+ Cmd::new(swaylock.bin.swaylock).args(&["--image", tmp_img]).exec()?;
7272+7373+ std::remove(tmp_img)?;
7474+ });
7575+ };
7676+7777+ struct DrvMeta {
7878+ name: String,
7979+ version: String,
8080+ description: String,
8181+8282+ platforms: Platforms,
8383+8484+ license: License,
8585+ homepage: Uri,
8686+8787+ maintainers: List<Maintainers>,
8888+ }
8989+ }
9090+9191+ mod build {
9292+ let unpack = BuildStep(|| {
9393+ let src: PathBuf = std::build::source();
9494+9595+ // unpack in cwd
9696+ match src.ext() {
9797+ ".tar.gz" | ".tgz" | ".tar.Z" => gzip(src),
9898+ ".tar.bz2" | ".tbz2" | ".tbz" => bzip2(src),
9999+ ".tar.xz" | ".tar.lzma" | ".txz" => xz(src),
100100+ _ => panic!("could not unpack")
101101+ }
102102+ });
103103+ }
104104+}
+6
examples/cur/crystal.rs
···11+/// all package derivations
22+mod pkgs {
33+ mod hello;
44+ mod libxkbcommon;
55+ mod sway;
66+}
+68
examples/cur/pkgs/hello.rs
···11+use std::derivation::{Derivation, DerivationMeta, BuildStep, Source};
22+33+// none
44+let build_step = BuildStep::new || {
55+ // call `./configure`
66+ std::build::???::configure();
77+ // call `make`
88+ std::build::make::???();
99+};
1010+1111+// special imperative block to act
1212+let install_step = BuildStep::new || {
1313+ let out: PathBuf = std::build::request_output_dir();
1414+1515+ std::install::make::install();
1616+};
1717+1818+let out = derivation.out();
1919+2020+pub let bin = out.join()
2121+2222+// special imperative block to act
2323+let install_check = BuildStep::new || {
2424+ let out: PathBuf = std::build::request_output_dir();
2525+ let hello_bin = out.join("bin/hello");
2626+2727+ std::check::is_present(hello_bin)?;
2828+2929+ std::check::exec(hello_bin, []);
3030+};
3131+3232+// ability to document derivations
3333+pub let hello = Derivation::new {
3434+ meta: DrvMeta::new {
3535+ name: "hello",
3636+ version: "2.12.1",
3737+ description: "Program that produces a familiar, friendly greeting",
3838+3939+ license: License::Gpl3Plus | License::Apache,
4040+4141+ // changelog, maintainers, platforms, etc.
4242+ // `mainProgram` makes no sense
4343+ },
4444+4545+ source: Source::fetch_url {
4646+ // interpolation vvvvvvvvvvvv
4747+ url: "mirror://gnu/hello/hello-{meta.version}.tar.gz",
4848+ // keep hash in source?
4949+ hash: "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=",
5050+ },
5151+5252+ // no hash in source
5353+ source: Source::fetch_url("mirror://gnu/hello/hello-{meta.version}.tar.gz"),
5454+5555+ // new starts from empty plan, could have `unpack` with first being unpack phase, `stdenv` for configure make make install workflows
5656+ steps: BuildPlan::new([
5757+ // see example down below
5858+ std::build::unpack(),
5959+ // patch step
6060+ // configure step
6161+ build_step,
6262+ // build check step
6363+ install_step,
6464+ // fixup step, patches files to work in nix??? envs
6565+ install_check, // could do some `bin/<name> -v` to ensure that linking worked fine
6666+ // distribution step
6767+ ]),
6868+};
···11-// # Ressources
22-// https://github.com/NixOS/nixpkgs/blob/master/doc/stdenv/stdenv.chapter.md
33-// ---
44-55-//! In separate crates/projects
66-77-/// tools for transforming data, building derivations
88-mod std/core {
99- // lib, build, install, etc.
1010-1111- mod derivation {
1212- // e.g. X is lspelling
1313- struct Drv<X> {
1414- meta: DrvMeta,
1515- source: Src,
1616- build_plan: BuildPlan,
1717-1818- more: X,
1919- }
2020- }
2121-2222- mod build {
2323- let unpack = BuildStep(|| {
2424- let src: PathBuf = std::build::source();
2525-2626- // unpack in cwd
2727- match src.ext() {
2828- ".tar.gz" | ".tgz" | ".tar.Z" => gzip(src),
2929- ".tar.bz2" | ".tbz2" | ".tbz" => bzip2(src),
3030- ".tar.xz" | ".tar.lzma" | ".txz" => xz(src),
3131- _ => panic!("could not unpack")
3232- }
3333- });
3434- }
3535-}
3636-3737-/// all package derivations
3838-mod pkgs {
3939- mod hello;
4040- mod libxkbcommon;
4141- mod sway;
4242-}
4343-4444-/// options definitions
4545-mod options {
4646- mod machine { }
4747- mod user { }
4848-}
+30
examples/machine/cristal.rs
···11+//! This whole file is an experiment to show how I would translate my own Nix
22+//! laptop config available at <https://github.com/mrnossiom/dotfiles/blob/main/flake.nix>
33+44+// this looks like deno http imports
55+// See <https://docs.deno.com/runtime/fundamentals/modules/#https-imports>
66+use "github:nixos/nixpkgs/nixos-24.11" as nixpkgs;
77+use "github:nixos/nixpkgs/nixos-unstable" as nixpkgs_unstable;
88+use "github:nix-community/home-manager/release-24.11" as home_manager;
99+1010+// versions of dependencies are frozen in a lockfile
1111+1212+use "github:LnL7/nix-darwin" as nix_darwin;
1313+use "github:ryantm/agenix" as agenix;
1414+use "github:nix-community/disko" as disko;
1515+use "github:nixos/nixos-hardware" as nixos_hardware;
1616+1717+/// options definitions
1818+mod options {
1919+ mod machine {}
2020+ mod user {}
2121+}
2222+2323+// could having `default` as a kw would be useful for many things
2424+2525+// should we explicitly export the item (like rust)? e.g. pub crystal = ...
2626+// should files return the last item (like nix)?
2727+// should we provide a default export (like js)? pub default = ... (where default is a kw)
2828+Crystal::new({
2929+3030+})
-69
examples/pkgs/hello.rs
···11-use std::derivation::{Derivation, DerivationMeta, BuildStep, Source};
22-33-pub let meta = DerivationMeta.new {
44- name: "hello",
55- version: "2.12.1",
66- description: "Program that produces a familiar, friendly greeting",
77-88- license: License::Gpl3Plus | License::Apache,
99-1010- // changelog, mainteners, platforms, etc.
1111- // `mainProgram` makes no sense
1212-};
1313-1414-let source = Source::fetch_url(_ {
1515- // interpolation vvvvvvvvvvvv
1616- url: "mirror://gnu/hello/hello-{meta.version}.tar.gz",
1717- // keep hash in source?
1818- hash: "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=",
1919-});
2020-2121-// none
2222-let build_step = BuildStep::new(|| {
2323- // call `./configure`
2424- std::build::???::configure();
2525- // call `make`
2626- std::build::make::???();
2727-});
2828-2929-// special imperative block to act
3030-let install_step = BuildStep::new(|| {
3131- // type is opt, just to show here
3232- let out: PathBuf = std::build::request_output_dir();
3333-3434- std::install::make::install();
3535-});
3636-3737-// special imperative block to act
3838-let install_check = BuildStep::new(|| {
3939- let out: PathBuf = std::build::request_output_dir();
4040- let hello_bin = out.join("bin/hello");
4141-4242- std::check::is_present(hello_bin)?;
4343-4444- std::check::exec(hello_bin, []);
4545-});
4646-4747-// ability to document derivations
4848-pub let derivation = Derivation::new(_ {
4949- meta,
5050- source,
5151-5252- // new starts from empty plan, could have `unpack` with first being unpack phase, `stdenv` for configure make make install workflows
5353- steps: BuildPlan::new([
5454- // see example down below
5555- std::build::unpack(),
5656- // patch step
5757- // configure step
5858- build_step,
5959- // build check step
6060- install_step,
6161- // fixup step, patches files to work in nix??? envs
6262- install_check, // could do some `bin/<name> -v` to ensure that linking worked fine
6363- // distribution step
6464- ]),
6565-});
6666-6767-let out = derivation.out();
6868-6969-pub let bin = out.join()