diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e0af74b..8182304 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,6 +1,20 @@ name: "Test RDE template" on: workflow_dispatch: # allows manual triggering + push: + paths: + - 'templates/rde/flake.lock' + - 'templates/rde/**/*.nix' + - 'templates/rde/**/*.sh' + - 'templates/rde/**/*.lua' + - '.github/workflows/check.yml' + pull_request: + paths: + - 'templates/rde/flake.lock' + - 'templates/rde/**/*.nix' + - 'templates/rde/**/*.sh' + - 'templates/rde/**/*.lua' + - '.github/workflows/check.yml' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/check_ed.yml b/.github/workflows/check_ed.yml index 497d060..350c013 100644 --- a/.github/workflows/check_ed.yml +++ b/.github/workflows/check_ed.yml @@ -1,16 +1,9 @@ -name: "Test ed template" +name: "Test ed template MacOS" on: - workflow_dispatch: + workflow_dispatch: # allows manual triggering push: - paths: - - 'templates/ed/**' - - 'tests/ed/**' - - '.github/workflows/check_ed.yml' - pull_request: - paths: - - 'templates/ed/**' - - 'tests/ed/**' - - '.github/workflows/check_ed.yml' + branches: + - 'update_rde' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -19,105 +12,15 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest] + os: [macos-latest, ubuntu-latest] steps: - uses: actions/checkout@v6 - uses: cachix/install-nix-action@v31 with: - github_access_token: ${{ github.token }} + github_access_token: ${{ secrets.GITHUB_TOKEN }} - uses: cachix/cachix-action@v17 with: name: rde authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' extraPullNames: rstats-on-nix, nix-community - - - name: Build template - run: nix build ./templates/ed - - - name: Test R script - env: - NO_NUSHELL: '1' - run: | - cd templates/ed - nix develop --command bash -c "Rscript ${{ github.workspace }}/tests/ed/test.R" - - - name: Test Python script (disabled by default) - env: - NO_NUSHELL: '1' - run: | - cd templates/ed - nix develop --command bash -c "python3 ${{ github.workspace }}/tests/ed/test.py" || echo "SKIP: Python packages not enabled" - - test-with-python: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - with: - github_access_token: ${{ github.token }} - - uses: cachix/cachix-action@v17 - with: - name: rde - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - extraPullNames: rstats-on-nix, nix-community - - - name: Setup test directory with Python enabled - run: | - TEST_DIR=$(mktemp -d) - cp -r templates/ed/. "$TEST_DIR/" - cd "$TEST_DIR" - sed -i 's/python[[:space:]]*=[[:space:]]*false;/python = true;/' flake.nix - grep -q "python[[:space:]]*=[[:space:]]*true;" flake.nix || { - echo "Error: Failed to enable Python in flake.nix" - exit 1 - } - echo "TEST_DIR=$TEST_DIR" >> $GITHUB_ENV - - - name: Build with Python enabled - run: | - cd "$TEST_DIR" - nix build - - - name: Test Python packages - env: - NO_NUSHELL: '1' - run: | - cd "$TEST_DIR" - nix develop --command bash -c "python3 ${{ github.workspace }}/tests/ed/test.py" - - test-with-julia: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - with: - github_access_token: ${{ github.token }} - - uses: cachix/cachix-action@v17 - with: - name: rde - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - extraPullNames: rstats-on-nix, nix-community - - - name: Setup test directory with Julia enabled - run: | - TEST_DIR=$(mktemp -d) - cp -r templates/ed/. "$TEST_DIR/" - cd "$TEST_DIR" - sed -i 's/julia[[:space:]]*=[[:space:]]*false;/julia = true;/' flake.nix - grep -q "julia[[:space:]]*=[[:space:]]*true;" flake.nix || { - echo "Error: Failed to enable Julia in flake.nix" - exit 1 - } - echo "TEST_DIR=$TEST_DIR" >> $GITHUB_ENV - - - name: Build with Julia enabled - run: | - cd "$TEST_DIR" - nix build - - - name: Test Julia packages - env: - NO_NUSHELL: '1' - run: | - cd "$TEST_DIR" - # nix develop --command bash -c "julia ${{ github.workspace }}/tests/ed/test.jl" + - run: nix build ./templates/ed diff --git a/.github/workflows/check_macos.yml b/.github/workflows/check_macos.yml index ad9d3ed..3b8e6f2 100644 --- a/.github/workflows/check_macos.yml +++ b/.github/workflows/check_macos.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: # allows manual triggering push: branches: - - 'update_ed' + - 'update_rde' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -23,4 +23,5 @@ jobs: name: rde authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' extraPullNames: rstats-on-nix, nix-community + - run: nix build ./templates/rde - run: nix build ./templates/ed diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 4b3cb00..96cb868 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -26,7 +26,7 @@ jobs: uses: DeterminateSystems/update-flake-lock@v28 with: token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} - branch: update_ed + branch: update_rde path-to-flake-dir: "templates/ed" pr-title: "Update RDE flake.lock" # Title of PR to be created pr-labels: | # Labels to be set on the PR diff --git a/templates/ed/.gitignore b/templates/ed/.gitignore index ffc0e1a..52e8a70 100644 --- a/templates/ed/.gitignore +++ b/templates/ed/.gitignore @@ -1,2 +1 @@ .nvimcom -.commandcode/ diff --git a/templates/ed/flake.lock b/templates/ed/flake.lock index feb65be..3180b2b 100644 --- a/templates/ed/flake.lock +++ b/templates/ed/flake.lock @@ -22,15 +22,15 @@ }, "nixpkgs": { "locked": { - "lastModified": 1779560665, - "narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", - "owner": "nixos", + "lastModified": 1779357205, + "narHash": "sha256-cCO8aTqss5x9Ky8GWkpY0Hy5fyTZEbtifSUV8QjSzic=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", + "rev": "f83fc3c307e74bc5fd5adb7eb6b8b13ffd2a36e1", "type": "github" }, "original": { - "owner": "nixos", + "owner": "NixOS", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" @@ -45,6 +45,7 @@ "nixpkgs" ], "plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references", + "plugins-r": "plugins-r", "r-nvim-nix": "r-nvim-nix", "rixpkgs": [ "rixpkgs" @@ -52,11 +53,11 @@ "wrappers": "wrappers" }, "locked": { - "lastModified": 1779544872, - "narHash": "sha256-AnuNQ9nbXrDYmL97TOejAds/FQOgD6FEOHABp/8dmsU=", + "lastModified": 1779519005, + "narHash": "sha256-R/tHAUf5XVuykMNvuOjeBizk/m+lWI7m1U2tAYIqaJs=", "owner": "dwinkler1", "repo": "nvimConfig", - "rev": "aec9110e709e1aa50d78f06293c4bde14974b23f", + "rev": "15efa3299a488acff7065843c1824d3dbfbdc193", "type": "github" }, "original": { @@ -81,25 +82,44 @@ "type": "github" } }, + "plugins-r": { + "flake": false, + "locked": { + "lastModified": 1776905071, + "narHash": "sha256-dXox6qEs1VDE7vPNDoN8bY4g06uj1IEs6uki72w8lpA=", + "owner": "R-nvim", + "repo": "R.nvim", + "rev": "582f2af11290ac067e49018db38e12a511325556", + "type": "github" + }, + "original": { + "owner": "R-nvim", + "ref": "v0.99.4", + "repo": "R.nvim", + "type": "github" + } + }, "r-nvim-nix": { "inputs": { "nixpkgs": [ "nvimConfig", "rixpkgs" ], - "rnvimsrc": "rnvimsrc" + "rnvimsrc": [ + "nvimConfig", + "plugins-r" + ] }, "locked": { - "lastModified": 1779438909, - "narHash": "sha256-1lvv0bdvSVyeCIgeZ7Ws7ffbDFurA5LJscS9dRLHzC8=", + "lastModified": 1779439280, + "narHash": "sha256-OX3/QTVOq5o3DD6dNzNY8X2v/7ZtbQOM01Z8bVf5tHc=", "owner": "dwinkler1", "repo": "r_nvim_nix", - "rev": "ec17e22ab362a0ddfd6c2e9c5e95d43897a143be", + "rev": "a012c98b5cc6a8ce59d461825c71b4877f934056", "type": "github" }, "original": { "owner": "dwinkler1", - "ref": "v0.99.4", "repo": "r_nvim_nix", "type": "github" } @@ -120,23 +140,6 @@ "type": "github" } }, - "rnvimsrc": { - "flake": false, - "locked": { - "lastModified": 1776905071, - "narHash": "sha256-dXox6qEs1VDE7vPNDoN8bY4g06uj1IEs6uki72w8lpA=", - "owner": "R-nvim", - "repo": "R.nvim", - "rev": "582f2af11290ac067e49018db38e12a511325556", - "type": "github" - }, - "original": { - "owner": "R-nvim", - "ref": "v0.99.4", - "repo": "R.nvim", - "type": "github" - } - }, "root": { "inputs": { "fran": "fran", @@ -153,11 +156,11 @@ ] }, "locked": { - "lastModified": 1779297405, - "narHash": "sha256-VFoBwH7ZjVxCnvZTb5ODRXt70sLtWMxstive0N+RS50=", + "lastModified": 1779512817, + "narHash": "sha256-Y2S3mvEezyKL/A4XUkgVbhuvob9YKfnG25NuJDl8fuQ=", "owner": "BirdeeHub", "repo": "nix-wrapper-modules", - "rev": "e7ed7a1205945befdf2e0d73ba7df91d935e5af1", + "rev": "8c90cbe3aaae094370b08f270682fc352fcbcb91", "type": "github" }, "original": { diff --git a/templates/ed/flake.nix b/templates/ed/flake.nix index 07603fa..b674c62 100644 --- a/templates/ed/flake.nix +++ b/templates/ed/flake.nix @@ -6,154 +6,196 @@ nixpkgs, nvimConfig, ... - }: let + } @ inputs: let + # ── Shared language support flags ────────────────────────────── + # Used by both the neovim wrapper module and the devShell + cats = { + clickhouse = false; + gitPlugins = false; + julia = false; + lua = false; + markdown = false; + nix = true; + optional = false; + python = false; + r = false; + }; + + # ── Language package lists ──────────────────────────────────── + # Shared between wrapper lang_packages and devShell toolchains. + # Accept pkgs so they work inside forAllSystems for each system. + + rPackages = pkgs: + (with pkgs.rpkgs.rPackages; [ + fixest + # pkgs.extraRPackages.musicMetadata + ]) + ++ ( + if builtins.pathExists ./r-packages.nix + # p: with p.rPackages; [ ... ] + then import ./r-packages.nix pkgs.rpkgs + else [] + ); + + pythonPackages = pkgs: + (with pkgs.python3Packages; [ + duckdb + polars + ]) + ++ ( + if builtins.pathExists ./python-packages.nix + # p: with p; [ ... ] + then import ./python-packages.nix pkgs.python3Packages + else [] + ); + + juliaPackages = + ["StatsBase"] + ++ ( + if builtins.pathExists ./julia-packages.nix + # [ ... ] + then import ./julia-packages.nix + else [] + ); + systems = ["aarch64-darwin" "x86_64-linux" "aarch64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - - mkPkgs = system: - import nixpkgs { - inherit system; - config.allowUnfree = true; - overlays = [nvimConfig.overlays.dependencies]; - }; - - projectModule = pkgs: let - baseConfig = nvimConfig.wrapperConfigs.default {inherit pkgs;}; - extraRPackages = - if builtins.pathExists ./r-packages.nix - then import ./r-packages.nix pkgs.rpkgs - else []; - - extraPythonPackages = - if builtins.pathExists ./python-packages.nix - then import ./python-packages.nix pkgs.python3Packages - else []; - - extraJuliaPackages = - if builtins.pathExists ./julia-packages.nix - then import ./julia-packages.nix - else []; - - projectName = builtins.baseNameOf (toString self.outPath); - in { - cats = { - clickhouse = false; - gitPlugins = false; - julia = false; - lua = false; - markdown = false; - nix = true; - optional = false; - python = false; - r = true; - }; - - settings = { - lang_packages = { - python = with pkgs.python3Packages; - [ - requests - ] - ++ extraPythonPackages; - - r = - (with pkgs.rpkgs.rPackages; [ - arrow - data_table - fixest - pkgs.nvimcom - ]) - ++ extraRPackages; - - julia = - ["StatsBase"] - ++ extraJuliaPackages; - }; - - colorscheme = "tokyonight"; #"kanagawa"; - background = "dark"; - wrapRc = true; - }; - - binName = "nv"; - - env.IS_PROJECT_EDITOR = "1"; - - catPkgs = { - always = [ - pkgs.git - pkgs.pre-commit - pkgs.cowsay - ]; - - nix = [ - pkgs.nil - pkgs.nixfmt - ]; - }; - - specs.extraLua = { - before = ["INIT_MAIN"]; - data = pkgs.writeText "project-startup.lua" '' - require("mini.notify").setup() - vim.notify = MiniNotify.make_notify() - vim.notify("Welcome to ${projectName}!") - ''; - }; - }; + overlays = [inputs.nvimConfig.overlays.dependencies]; in { - formatter = forAllSystems (system: (mkPkgs system).nixfmt-tree); + formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-rfc-style); packages = forAllSystems (system: let - pkgs = mkPkgs system; - in { - default = nvimConfig.lib.mkWrapper { - inherit pkgs; - modules = [(projectModule pkgs)]; + pkgs = import nixpkgs { + inherit system overlays; + config = {allowUnfree = true;}; }; + # Plain attrset — pkgs is captured from the surrounding scope, + # so the module system does not need lazy _module.args resolution. + projectSettings = { + inherit cats; + settings = let + # With `replace` packages are replaced otherwise they are merged with base packages + replace = pkgs.lib.mkForce; + in { + lang_packages = { + python = replace (pythonPackages pkgs); + r = replace (rPackages pkgs); + julia = replace juliaPackages; + }; + colorscheme = "kanagawa"; + background = "dark"; + wrapRc = true; + }; + binName = "nv"; + + env = { + IS_PROJECT_EDITOR = "1"; + }; + + runtimePkgs = with pkgs; [ + cowsay + ]; + + specs.extraLua = let + name = builtins.baseNameOf (builtins.toString ./.); + in { + data = pkgs.vimPlugins.mini-notify; + before = ["INIT_MAIN"]; + config = '' + require("mini.notify").setup() + vim.notify = MiniNotify.make_notify() + vim.notify("Welcome to ${name}!") + ''; + }; + }; + evalResult = nvimConfig.inputs.wrappers.lib.evalModules { + modules = [ + nvimConfig.wrapperModules.default + projectSettings + ]; + }; + in { + default = evalResult.config.wrap {inherit pkgs;}; }); devShells = forAllSystems (system: let - pkgs = mkPkgs system; - evalResult = nvimConfig.lib.eval { - inherit pkgs; - modules = [(projectModule pkgs)]; + pkgs = import nixpkgs { + inherit system overlays; + config = {allowUnfree = true;}; }; - nv = evalResult.config.wrap {inherit pkgs;}; + nv = self.packages.${system}.default; in { default = pkgs.mkShell { + shellHook = '' + exec nu + alias gst='git status' + alias glol='git log --oneline --graph --decorate' + alias gc='git commit' + alias gl='git pull' + alias gp='git push' + ''; packages = [ nv + pkgs.git + pkgs.pre-commit pkgs.nushell ] - ++ nvimConfig.lib.devShellPackages evalResult.config; - shellHook = - nvimConfig.lib.shellHook evalResult.config - + '' - if [ -z "''${NO_NUSHELL:-}" ]; then - exec nu - fi - ''; + # ── R toolchain (R REPL, quarto, LSP, formatter) ───── + ++ pkgs.lib.optionals cats.r (let + r_packages = (pkgs.baseRPackages or []) ++ rPackages pkgs; + in [ + (pkgs.rWrapper.override {packages = r_packages;}) + pkgs.radianWrapper + pkgs.air-formatter + pkgs.yaml-language-server + pkgs.nvimcom + pkgs.rnvimserver + ]) + # ── Python toolchain (interpreter, LSP, formatter) ──── + ++ pkgs.lib.optionals cats.python [ + (pkgs.python3.withPackages (ps: pkgs.basePythonPackages ps ++ pythonPackages pkgs)) + pkgs.nodejs + pkgs.ruff + pkgs.basedpyright + pkgs.uv + ] + # ── Julia toolchain ─────────────────────────────────── + ++ pkgs.lib.optionals cats.julia [ + pkgs.julia-bin.withPackages + juliaPackages + ] + # ── Markdown toolchain (quarto, zk) ─────────────────── + ++ (let + r_packages = (pkgs.baseRPackages or []) ++ rPackages pkgs; + quarto = + if cats.r + then pkgs.quarto.override {extraRPackages = r_packages;} + else pkgs.quarto; + in + pkgs.lib.optionals cats.markdown [ + pkgs.python313Packages.pylatexenc + quarto + pkgs.zk + ]); }; }); }; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e"; - fran = { url = "github:dwinkler1/fran"; - inputs.nixpkgs.follows = "rixpkgs"; + inputs = { + nixpkgs.follows = "rixpkgs"; + }; }; - nvimConfig = { url = "github:dwinkler1/nvimConfig"; inputs = { - nixpkgs.follows = "nixpkgs"; rixpkgs.follows = "rixpkgs"; + nixpkgs.follows = "nixpkgs"; fran.follows = "fran"; }; }; diff --git a/tests/ed/test.R b/tests/ed/test.R deleted file mode 100755 index ad2967a..0000000 --- a/tests/ed/test.R +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env Rscript - -packages <- c("arrow", "data.table", "fixest", "nvimcom") -failed <- character(0) - -for (pkg in packages) { - ok <- tryCatch( - { - # nvimcom requires Neovim; skip loading but check it's installed - if (pkg == "nvimcom") { - requireNamespace(pkg, quietly = TRUE) - } else { - library(pkg, character.only = TRUE, quietly = TRUE) - } - TRUE - }, - error = function(e) FALSE - ) - if (!ok) { - failed <- c(failed, pkg) - } -} - -if (length(failed) > 0) { - cat(sprintf("FAIL: %s\n", paste(failed, collapse = ", "))) - quit(status = 1) -} - -cat("PASS: all packages loaded\n") diff --git a/tests/ed/test.jl b/tests/ed/test.jl deleted file mode 100755 index 5971f80..0000000 --- a/tests/ed/test.jl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env julia - -packages = ["StatsBase"] -failed = String[] - -for pkg in packages - try - @eval using $pkg - catch - push!(failed, pkg) - end -end - -if !isempty(failed) - @error "FAIL: $(join(failed, ", "))" - exit(1) -end - -println("PASS: all packages loaded") diff --git a/tests/ed/test.py b/tests/ed/test.py deleted file mode 100755 index b893419..0000000 --- a/tests/ed/test.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -import sys - -packages = ["requests"] -failed = [] - -for pkg in packages: - try: - __import__(pkg) - except ImportError: - failed.append(pkg) - -if failed: - sys.stderr.write(f"FAIL: {', '.join(failed)}\n") - sys.exit(1) - -print("PASS: all packages loaded")