commit 3393f1ecfe7f21a30a02af4fdb197ae2c75917d5 Author: atagen Date: Sat Nov 23 16:49:05 2024 +1100 first release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8fa2eea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +_build +.direnv/ +.envrc diff --git a/bin/.ocamlformat b/bin/.ocamlformat new file mode 100644 index 0000000..e69de29 diff --git a/bin/dune b/bin/dune new file mode 100644 index 0000000..b1f555a --- /dev/null +++ b/bin/dune @@ -0,0 +1,4 @@ +(executable + (public_name meat) + (name main) + (libraries meat)) diff --git a/bin/main.ml b/bin/main.ml new file mode 100644 index 0000000..cdbde92 --- /dev/null +++ b/bin/main.ml @@ -0,0 +1,16 @@ +open Meat + +let () = + print_int (Array.length Sys.argv); + if Array.length Sys.argv >= 2 then ( + print_endline " args. contents:"; + Array.iter print_endline Sys.argv; + match String.lowercase_ascii (Array.get Sys.argv 1) with + | "yum" -> yum () + | "cook" -> cook () + | "poke" -> poke () + | "gut" -> gut () + | "look" -> look () + | "fresh" -> fresh () + | _ -> help () + ) else help (); diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..1a97c3c --- /dev/null +++ b/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.17) + +(name meat) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name ") + +(maintainers "Maintainer Name ") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name meat) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml dune) + (tags + ("add topics" "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f3b3467 --- /dev/null +++ b/flake.lock @@ -0,0 +1,239 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flakey-profile": { + "locked": { + "lastModified": 1712898590, + "narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=", + "owner": "lf-", + "repo": "flakey-profile", + "rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d", + "type": "github" + }, + "original": { + "owner": "lf-", + "repo": "flakey-profile", + "type": "github" + } + }, + "lix": { + "flake": false, + "locked": { + "lastModified": 1732112222, + "narHash": "sha256-H7GN4++a4vE49SUNojZx+FSk4mmpb2ifJUtJMJHProI=", + "rev": "66f6dbda32959dd5cf3a9aaba15af72d037ab7ff", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/66f6dbda32959dd5cf3a9aaba15af72d037ab7ff.tar.gz?rev=66f6dbda32959dd5cf3a9aaba15af72d037ab7ff" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/lix/archive/main.tar.gz" + } + }, + "lix-module": { + "inputs": { + "flake-utils": "flake-utils_2", + "flakey-profile": "flakey-profile", + "lix": [ + "lix" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1731967274, + "narHash": "sha256-n6dPGRlMGdL8X5gviA6ZuRfUdbdD5KiNN/BpABA5YT0=", + "rev": "aa2846680fa9a2032939d720487942567fd9eb63", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/aa2846680fa9a2032939d720487942567fd9eb63.tar.gz?rev=aa2846680fa9a2032939d720487942567fd9eb63" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/nixos-module/archive/main.tar.gz" + } + }, + "nh": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1732089528, + "narHash": "sha256-+yXeJiSFn96pW6H/50DfCfZiOLSfZNGhK7R4f0aUvGY=", + "owner": "viperML", + "repo": "nh", + "rev": "cff51af0ebb09227070b0332c598c7a4b7f8175a", + "type": "github" + }, + "original": { + "owner": "viperML", + "repo": "nh", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1731386116, + "narHash": "sha256-lKA770aUmjPHdTaJWnP3yQ9OI1TigenUqVC3wweqZuI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "689fed12a013f56d4c4d3f612489634267d86529", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1730359060, + "narHash": "sha256-Hkk0mf4pgvX9Ut0YA397nsFqMLhzFVBdFHc4PhBrxYE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e19cfce6f3f08d07653157d8826f5c920c770d7b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e19cfce6f3f08d07653157d8826f5c920c770d7b", + "type": "github" + } + }, + "ocaml-overlay": { + "inputs": { + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1730414122, + "narHash": "sha256-eAfo1XsQMdKuiOOhqCuai7vpIBH8S4ll7Sm4BP/M58c=", + "owner": "nix-ocaml", + "repo": "nix-overlays", + "rev": "1de1cabdb68cbc667dd48da2f128c2df6d5fe604", + "type": "github" + }, + "original": { + "owner": "nix-ocaml", + "repo": "nix-overlays", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "lix": "lix", + "lix-module": "lix-module", + "nh": "nh", + "nixpkgs": [ + "ocaml-overlay", + "nixpkgs" + ], + "ocaml-overlay": "ocaml-overlay" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..56c5bee --- /dev/null +++ b/flake.nix @@ -0,0 +1,112 @@ +{ + inputs = { + nixpkgs.follows = "ocaml-overlay/nixpkgs"; + + ocaml-overlay = { + url = "github:nix-ocaml/nix-overlays"; + }; + + flake-utils.url = "github:numtide/flake-utils"; + + nh.url = "github:viperML/nh"; + + lix = { + url = "https://git.lix.systems/lix-project/lix/archive/main.tar.gz"; + flake = false; + }; + + lix-module = { + url = "https://git.lix.systems/lix-project/nixos-module/archive/main.tar.gz"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.lix.follows = "lix"; + }; + }; + + outputs = inputs @ { + self, + nixpkgs, + flake-utils, + ocaml-overlay, + ... + }: let + inherit (inputs) nixpkgs; + lix-overlay = inputs.lix-module.overlays.default; + lix-module = inputs.lix-module.nixosModules.default; + nh-overlay = inputs.nh.overlays.default; + in + flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs { + inherit system; + overlays = [ + ocaml-overlay.overlays.default + lix-overlay + nh-overlay + ]; + modules = [lix-module]; + extra-substituters = "https://anmonteiro.nix-cache.workers.dev"; + extra-trusted-public-keys = "ocaml.nix-cache.com-1:/xI2h2+56rwFfKyyFVbkJSeGqSIYMC/Je+7XXqGKDIY="; + }; + minimal = let + inherit (pkgs) ocaml-ng; + inherit + (ocaml-ng.ocamlPackages_5_2) + dune_3 + ocaml + ; + in [ + dune_3 + ocaml + ]; + dev = let + inherit (pkgs) ocaml-ng; + inherit + (ocaml-ng.ocamlPackages_5_2) + utop + ocaml-lsp + ocamlformat + ocamlformat-rpc-lib + ; + in [ + utop + ocaml-lsp + ocamlformat + ocamlformat-rpc-lib + ]; + inherit (pkgs) lix nh; + in { + devShells.default = let + inherit (pkgs) mkShell; + in + mkShell { + buildInputs = minimal ++ dev ++ [lix nh]; + }; + + packages.default = pkgs.callPackage ./nix/default.nix {ocaml-deps = minimal;}; + + defaultPackage = self.packages.${system}.default; + } + ) + // { + nixosModules.meat = import ./nix/module.nix { + meatOverlays = [self.overlays.meat nh-overlay]; + lixModule = lix-module; + }; + + overlays.meat = final: _prev: let + ocaml-deps = let + inherit (final) ocaml-ng; + inherit + (ocaml-ng.ocamlPackages_5_2) + dune_3 + ocaml + ; + in [ + dune_3 + ocaml + ]; + in { + meat = final.callPackage ./nix/default.nix {inherit ocaml-deps;}; + }; + }; +} diff --git a/lib/.ocamlformat b/lib/.ocamlformat new file mode 100644 index 0000000..e69de29 diff --git a/lib/dune b/lib/dune new file mode 100644 index 0000000..2b63e36 --- /dev/null +++ b/lib/dune @@ -0,0 +1,3 @@ +(library + (name meat) + (libraries unix)) diff --git a/lib/meat.ml b/lib/meat.ml new file mode 100644 index 0000000..77b6b35 --- /dev/null +++ b/lib/meat.ml @@ -0,0 +1,124 @@ +let header = "\n ----- MEAT ----------------------------------------\n" +let footer = "\n ---------------------------------------------------\n" + +let help = + "\n\ + \tYUM - CONSUME DELICIOUS MEATS\n\ + \tCOOK - ONLY PREPARE MEATS\n\ + \tPOKE - TASTE SUSPICIOUS MEATS\n\ + \tGUT - CLEAN MEAT STORES\n\ + \tLOOK - INSPECT MEAT\n\ + \tFRESH - HUNT LATEST MEATS\n\ + \t ..N - ..LATEST SUBMEATS OF N\n\ + \t ..-A - ..HUNT ALL SUBMEATS\n" + +open Sys + +let pass_args () = + let len = Array.length argv and sconcat acc el = acc ^ " " ^ el in + match len with + | 3 -> argv.(2) + | n when n > 3 -> + print_int (n - 1); + Array.fold_left sconcat "" (Array.sub argv 2 (n - 2)) + | _ -> "" + +let do_cmd ?(args = true) cmd = + match command (if args then cmd ^ pass_args () else cmd) with _ -> () + +let meat_print text = print_endline ("\n \t" ^ text ^ "\n") + +let yum () = + print_string header; + meat_print "CONSUMING DELICIOUS MEATS.."; + do_cmd "nh os switch"; + print_string footer + +let cook () = + print_string header; + meat_print "PREPARING DELICIOUS MEATS.."; + do_cmd "nh os build"; + print_string footer + +let poke () = + print_string header; + meat_print "PREPARING SUSPICIOUS MEATS.."; + do_cmd "nh os build --show-trace"; + print_string footer + +let gut () = + print_string header; + meat_print "CLEANING MEAT STORES.."; + do_cmd "nh clean all"; + print_string footer + +let look () = + print_string header; + meat_print "INSPECTING MEAT.."; + do_cmd "nix flake info --flake $NH_FLAKE"; + print_string footer + +let all_flag () = Array.mem "-a" argv || Array.mem "--all" argv +let derelativise base = List.map (fun a -> base ^ "/" ^ a) + +let filter_dirs fullpath dirs = + dirs |> derelativise fullpath + |> List.filter (fun d -> (Unix.stat d).st_kind = S_DIR) + +let walk ?(include_base = false) entry = + let rec loop dir : string list = + let contents = Sys.readdir dir |> Array.to_list in + let is_flake = List.mem "flake.nix" contents in + if dir = entry && not include_base then + let subdirs = contents |> filter_dirs dir in + List.flatten (List.map loop subdirs) + else if is_flake || (dir = entry && include_base) then + let subdirs = contents |> filter_dirs dir in + let children = List.flatten (List.map loop subdirs) in + [ dir ] @ children + else [] + in + loop entry + +let countdepth s = + s |> String.fold_left (fun acc el -> acc + if el = '/' then 1 else 0) 0 + +let compdepth a b = + let ad = countdepth a and bd = countdepth b in + let dif = ad - bd in + match dif with 0 -> 0 | _ -> dif / abs dif + +let allcaps s = + String.map (fun c -> Char.uppercase_ascii c) s + +let fresh () = + print_string header; + meat_print "HUNTING FRESH MEATS.."; + print_string footer; + let argv_len = Array.length argv in + let root = Sys.getenv "NH_FLAKE" in + let base_dir = root ^ "/flakes" in + let update = + if all_flag () then walk base_dir |> List.sort compdepth |> List.rev + else if argv_len >= 3 then + let subflakes = + match argv_len with + | 3 -> [ argv.(2) ] + | _ -> Array.sub argv 2 (argv_len - 2) |> Array.to_list + in + subflakes |> derelativise base_dir + |> List.map (walk ~include_base:true) + |> List.flatten |> List.sort compdepth |> List.rev + else [] + in + update @ [ root ] + |> List.iter (fun d -> + if d != root then + (meat_print ("PROCESSING SUBMEAT " ^ (String.split_on_char '/' d |> List.rev |> List.hd |> allcaps) ^ "..");) + else + meat_print ("PROCESSING FRESH MEATS.."); + do_cmd ~args:false ("nix flake update --flake " ^ d); + print_string footer;); + print_newline () + +let help () = print_string (header ^ help ^ footer) diff --git a/meat.opam b/meat.opam new file mode 100644 index 0000000..fe4df60 --- /dev/null +++ b/meat.opam @@ -0,0 +1,31 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name "] +authors: ["Author Name "] +license: "LICENSE" +tags: ["add topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "ocaml" + "dune" {>= "3.17"} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..26dd7ff --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,18 @@ +{ + pkgs, + lib, + ocamlPackages, + ocaml-deps, + nh, + nix, + ... +}: +ocamlPackages.buildDunePackage { + pname = "meat"; + version = "delicious-0.1"; + + minimalOCamlVersion = "5.2"; + + src = ./..; + buildInputs = ocaml-deps; +} diff --git a/nix/meat-module.nix b/nix/meat-module.nix new file mode 100644 index 0000000..9241d68 --- /dev/null +++ b/nix/meat-module.nix @@ -0,0 +1,30 @@ +{ + pkgs, + lib, + config, + ... +}: let + inherit (lib) mkEnableOption mkOption types; + cfg = config.programs.meat; +in { + options.programs.meat = { + enable = mkEnableOption "meat"; + flake = mkOption { + type = with types; nullOr (either path str); + default = null; + description = "path to your system flake"; + }; + }; + config = let + inherit (pkgs) meat nh lix; + in + lib.mkIf + cfg.enable + { + environment.systemPackages = [meat nh lix]; + environment.sessionVariables.NH_FLAKE = + if (cfg.flake == null) + then abort "Please set the programs.meat.flake option to your system flake." + else config.programs.meat.flake; + }; +} diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 0000000..d30769b --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,7 @@ +{ + meatOverlays, + lixModule, +}: { + imports = [./meat-module.nix lixModule]; + nixpkgs.overlays = meatOverlays; +} diff --git a/test/dune b/test/dune new file mode 100644 index 0000000..249a645 --- /dev/null +++ b/test/dune @@ -0,0 +1,2 @@ +(test + (name test_meat)) diff --git a/test/test_meat.ml b/test/test_meat.ml new file mode 100644 index 0000000..e69de29