docs: update beam.section

+102 -49
+102 -49
doc/languages-frameworks/beam.section.md
··· 68 69 `mixRelease` is used to make a release in the mix sense. Dependencies will need to be fetched with `fetchMixDeps` and passed to it. 70 71 - #### mixRelease - Elixir Phoenix example {#mixrelease---elixir-phoenix-example} 72 73 - Here is how your `default.nix` file would look. 74 75 ```nix 76 with import <nixpkgs> { }; 77 78 let 79 packages = beam.packagesWith beam.interpreters.erlang; 80 src = builtins.fetchgit { 81 url = "ssh://git@github.com/your_id/your_repo"; 82 rev = "replace_with_your_commit"; 83 }; 84 85 - pname = "your_project"; 86 - version = "0.0.1"; 87 - mixEnv = "prod"; 88 - 89 mixFodDeps = packages.fetchMixDeps { 90 pname = "mix-deps-${pname}"; 91 - inherit src mixEnv version; 92 # nix will complain and tell you the right value to replace this with 93 sha256 = lib.fakeSha256; 94 # if you have build time environment variables add them here ··· 97 98 nodeDependencies = (pkgs.callPackage ./assets/default.nix { }).shell.nodeDependencies; 99 100 - frontEndFiles = stdenvNoCC.mkDerivation { 101 - pname = "frontend-${pname}"; 102 - 103 - nativeBuildInputs = [ nodejs ]; 104 - 105 - inherit version src; 106 - 107 - buildPhase = '' 108 - cp -r ./assets $TEMPDIR 109 - 110 - mkdir -p $TEMPDIR/assets/node_modules/.cache 111 - cp -r ${nodeDependencies}/lib/node_modules $TEMPDIR/assets 112 - export PATH="${nodeDependencies}/bin:$PATH" 113 - 114 - cd $TEMPDIR/assets 115 - webpack --config ./webpack.config.js 116 - cd .. 117 - ''; 118 - 119 - installPhase = '' 120 - cp -r ./priv/static $out/ 121 - ''; 122 - 123 - outputHashAlgo = "sha256"; 124 - outputHashMode = "recursive"; 125 - # nix will complain and tell you the right value to replace this with 126 - outputHash = lib.fakeSha256; 127 - 128 - impureEnvVars = lib.fetchers.proxyImpureEnvVars; 129 - }; 130 - 131 - 132 in packages.mixRelease { 133 - inherit src pname version mixEnv mixFodDeps; 134 # if you have build time environment variables add them here 135 MY_ENV_VAR="my_value"; 136 - preInstall = '' 137 - mkdir -p ./priv/static 138 - cp -r ${frontEndFiles} ./priv/static 139 ''; 140 } 141 ``` ··· 165 systemd.services.${release_name} = { 166 wantedBy = [ "multi-user.target" ]; 167 after = [ "network.target" "postgresql.service" ]; 168 requires = [ "network-online.target" "postgresql.service" ]; 169 description = "my app"; 170 environment = { ··· 201 path = [ pkgs.bash ]; 202 }; 203 204 environment.systemPackages = [ release ]; 205 } 206 ``` ··· 215 { pkgs ? import <nixpkgs> {} }: 216 217 with pkgs; 218 - 219 let 220 - 221 - elixir = beam.packages.erlangR22.elixir_1_9; 222 - 223 in 224 mkShell { 225 buildInputs = [ elixir ]; 226 - 227 - ERL_INCLUDE_PATH="${erlang}/lib/erlang/usr/include"; 228 } 229 ``` 230 ··· 264 # TODO: not sure how to make hex available without installing it afterwards. 265 mix local.hex --if-missing 266 export LANG=en_US.UTF-8 267 export ERL_AFLAGS="-kernel shell_history enabled" 268 269 # postges related
··· 68 69 `mixRelease` is used to make a release in the mix sense. Dependencies will need to be fetched with `fetchMixDeps` and passed to it. 70 71 + #### mixRelease - Elixir Phoenix example {#mix-release-elixir-phoenix-example} 72 + 73 + there are 3 steps, frontend dependencies (javascript), backend dependencies (elixir) and the final derivation that puts both of those together 74 + 75 + ##### mixRelease - Frontend dependencies (javascript) {#mix-release-javascript-deps} 76 + 77 + for phoenix projects, inside of nixpkgs you can either use yarn2nix (mkYarnModule) or node2nix. An example with yarn2nix can be found [here](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/web-apps/plausible/default.nix#L39). An example with node2nix will follow. To package something outside of nixpkgs, you have alternatives like [npmlock2nix](https://github.com/nix-community/npmlock2nix) or [nix-npm-buildpackage](https://github.com/serokell/nix-npm-buildpackage) 78 + 79 + ##### mixRelease - backend dependencies (mix) {#mix-release-mix-deps} 80 + 81 + There are 2 ways to package backend dependencies. With mix2nix and with a fixed-output-derivation (FOD). 82 + 83 + ###### mix2nix {#mix2nix} 84 + 85 + mix2nix is a cli tool available in nixpkgs. it will generate a nix expression from a mix.lock file. It is quite standard in the 2nix tool series. 86 + 87 + Note that currently mix2nix can't handle git dependencies inside the mix.lock file. If you have git dependencies, you can either add them manually (see [example](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/pleroma/default.nix#L20)) or use the FOD method. 88 + 89 + The advantage of using mix2nix is that nix will know your whole dependency graph. On a dependency update, this won't trigger a full rebuild and download of all the dependencies, where FOD will do so. 90 + 91 + practical steps: 92 + 93 + - run `mix2nix > mix_deps.nix` in the upstream repo. 94 + - pass `mixNixDeps = with pkgs; import ./mix_deps.nix { inherit lib beamPackages; };` as an argument to mixRelease. 95 + 96 + If there are git depencencies. 97 + 98 + - You'll need to fix the version artificially in mix.exs and regenerate the mix.lock with fixed version (on upstream). This will enable you to run `mix2nix > mix_deps.nix`. 99 + - From the mix_deps.nix file, remove the dependencies that had git versions and pass them as an override to the import function. 100 + 101 + ```nix 102 + mixNixDeps = import ./mix.nix { 103 + inherit beamPackages lib; 104 + overrides = (final: prev: { 105 + # mix2nix does not support git dependencies yet, 106 + # so we need to add them manually 107 + prometheus_ex = beamPackages.buildMix rec { 108 + name = "prometheus_ex"; 109 + version = "3.0.5"; 110 + 111 + # Change the argument src with the git src that you actually need 112 + src = fetchFromGitLab { 113 + domain = "git.pleroma.social"; 114 + group = "pleroma"; 115 + owner = "elixir-libraries"; 116 + repo = "prometheus.ex"; 117 + rev = "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"; 118 + sha256 = "1v0q4bi7sb253i8q016l7gwlv5562wk5zy3l2sa446csvsacnpjk"; 119 + }; 120 + # you can re-use the same beamDeps argument as generated 121 + beamDeps = with final; [ prometheus ]; 122 + }; 123 + }); 124 + }; 125 + ``` 126 + 127 + You will need to run the build process once to fix the sha256 to correspond to your new git src. 128 + 129 + ###### FOD {#fixed-output-derivation} 130 + 131 + A fixed output derivation will download mix dependencies from the internet. To ensure reproducibility, a hash will be supplied. Note that mix is relatively reproducible. An FOD generating a different hash on each run hasn't been observed (as opposed to npm where the chances are relatively high). See [elixir_ls](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/beam-modules/elixir_ls.nix) for a usage example of FOD. 132 + 133 + Practical steps 134 + 135 + - start with the following argument to mixRelease 136 + 137 + ```nix 138 + mixFodDeps = fetchMixDeps { 139 + pname = "mix-deps-${pname}"; 140 + inherit src version; 141 + sha256 = lib.fakeSha256; 142 + }; 143 + ``` 144 + 145 + The first build will complain about the sha256 value, you can replace with the suggested value after that. 146 + 147 + Note that if after you've replaced the value, nix suggests another sha256, then mix is not fetching the dependencies reproducibly. An FOD will not work in that case and you will have to use mix2nix. 148 149 + ##### mixRelease - example {#mix-release-example} 150 + 151 + Here is how your `default.nix` file would look for a phoenix project. 152 153 ```nix 154 with import <nixpkgs> { }; 155 156 let 157 + # beam.interpreters.erlangR23 is available if you need a particular version 158 packages = beam.packagesWith beam.interpreters.erlang; 159 + 160 + pname = "your_project"; 161 + version = "0.0.1"; 162 + 163 src = builtins.fetchgit { 164 url = "ssh://git@github.com/your_id/your_repo"; 165 rev = "replace_with_your_commit"; 166 }; 167 168 + # if using mix2nix you can use the mixNixDeps attribute 169 mixFodDeps = packages.fetchMixDeps { 170 pname = "mix-deps-${pname}"; 171 + inherit src version; 172 # nix will complain and tell you the right value to replace this with 173 sha256 = lib.fakeSha256; 174 # if you have build time environment variables add them here ··· 177 178 nodeDependencies = (pkgs.callPackage ./assets/default.nix { }).shell.nodeDependencies; 179 180 in packages.mixRelease { 181 + inherit src pname version mixFodDeps; 182 # if you have build time environment variables add them here 183 MY_ENV_VAR="my_value"; 184 + 185 + postBuild = '' 186 + ln -sf ${nodeDependencies}/lib/node_modules assets/node_modules 187 + npm run deploy --prefix ./assets 188 + 189 + # for external task you need a workaround for the no deps check flag 190 + # https://github.com/phoenixframework/phoenix/issues/2690 191 + mix do deps.loadpaths --no-deps-check, phx.digest 192 + mix phx.digest --no-deps-check 193 ''; 194 } 195 ``` ··· 219 systemd.services.${release_name} = { 220 wantedBy = [ "multi-user.target" ]; 221 after = [ "network.target" "postgresql.service" ]; 222 + # note that if you are connecting to a postgres instance on a different host 223 + # postgresql.service should not be included in the requires. 224 requires = [ "network-online.target" "postgresql.service" ]; 225 description = "my app"; 226 environment = { ··· 257 path = [ pkgs.bash ]; 258 }; 259 260 + # in case you have migration scripts or you want to use a remote shell 261 environment.systemPackages = [ release ]; 262 } 263 ``` ··· 272 { pkgs ? import <nixpkgs> {} }: 273 274 with pkgs; 275 let 276 + elixir = beam.packages.erlangR24.elixir_1_12; 277 in 278 mkShell { 279 buildInputs = [ elixir ]; 280 } 281 ``` 282 ··· 316 # TODO: not sure how to make hex available without installing it afterwards. 317 mix local.hex --if-missing 318 export LANG=en_US.UTF-8 319 + # keep your shell history in iex 320 export ERL_AFLAGS="-kernel shell_history enabled" 321 322 # postges related