Operand

op allah, geez.

gram: pool

> ./gram/elixir.nix

Lenses
(coming soon!)


{ channel, base, codebase, name, user, dependencies ? [], app ? name, ... }:
{ pkgs, ... }:
let
  home = "/var/gram";
  command = call: nd "_build/prod/rel/${app}/bin/${app} ${call}";
  cron = "(sh -c 'date -Is' | str trim)";
  place = "${home}/run/${name}";

  nd = cmd:
  ''
    ${measures.load}
    ${cmd}
  '';

  nu = name: body: pkgs.writeScriptBin name ''
    #!${pkgs.nushell}/bin/nu
    ${body}
  '';

  measures = {
    load = ''
      cd ${place}/run;
      load-env (open /var/gram/${name}.call | lines | split column '=' | transpose -i -r --as-record);
    '';

    clone = ''
      let source = $"${place}/${cron}"; mkdir ${place}
      ${pkgs.git}/bin/git clone ${codebase} $source
      # ${pkgs.rsync}/bin/rsync -av ${codebase}/ $source

      if ("/var/share/gram/${name}/share" | path exists) {
        ${pkgs.rsync}/bin/rsync -a /var/share/gram/${name}/share $source
      } else { mkdir ([$source share ] | path join)}

      # let node = (ls ($source | into glob)).name.0
      # tree -dafix --noreport $node | lines | each {|n| try { chmod 777 $n } }

      try { ${pkgs.rsync}/bin/rsync -a ${place}/run/_build $source }
      try { rm ${place}/run }; ln -s $source ${place}/run

      ${measures.load}
      mkdir ${place}/deps
      mkdir ${place}/node_modules
      try { cp ${home}/gram/${name}.call ${place}/run/.call }
      chmod 765 ${place}/run/assets/
      ln -s ${place}/deps ${place}/run/deps
      ln -s ${place}/node_modules ${place}/run/assets/node_modules
      if ("${place}/run/static/assets/" | path exists) {
        chmod -R 765 ${place}/run/static/assets/ }
    '';

    prepare = ''
      ${measures.load}
      ${nd "${pkgs.elixir}/bin/mix deps.get"}
      # ...
      if ("${place}/run/assets/yarn.lock" | path exists) {
        chmod 664 ${place}/run/assets/yarn.lock
        ${nd "yarn --cwd assets install --production"}
        chmod 664 ${place}/run/assets/yarn.lock
      }
      ${pkgs.tree}/bin/tree -afix --noreport ${place}/run/priv/static | lines | where { ($in | path type) == file } | each { chmod 664 $in }
      ${nd "${pkgs.elixir}/bin/mix setup"}
      ${nd "${pkgs.elixir}/bin/mix assets.build"}
    '';

    spinup = ''
      ${measures.load}
      if ("${place}/run/assets/yarn.lock" | path exists) {
        chmod 664 ${place}/run/assets/yarn.lock
        ${nd "yarn --cwd assets install --production"}
        chmod 664 ${place}/run/assets/yarn.lock
      }
      tree -afix --noreport ${place}/run/priv/static | lines | where { ($in | path type) == file } | each { chmod 664 $in }
      ${nd "${pkgs.elixir}/bin/mix assets.build"}
    '';

    spin = with measures; ''
      ${clone}
      ${spinup}
      ${close}
      ${command "daemon"}
    '';

    run = with measures; ''
      ${clone}
      ${prepare}
      ${cycle}
    '';

    cycle = with measures; ''
      ${nd "${pkgs.elixir}/bin/mix release"}
      ${close}
      ${command "daemon"}
    '';

    close = "try { ${close_channel channel} }";

    do = ''
    def main --wrapped [ ...call: string ] {
      ${command "...($call)"}
    }'';
  };

  close_channel = channel: ''
  let process = (
      netstat -tunlp | tail -n+3 | lines |
      split column -r ' +' |
      where column7 =~ $"/("beam")" |
      where column4 =~ ":${toString channel}" |
      get column7 | split row "/" | get 0 | into int
    ); kill $process
  '';

in {
  environment.systemPackages = with pkgs; with measures; [
    (nu "clone-${name}" clone)
    (nu "load-${name}" load)
    (nu "prepare-${name}" prepare)
    (nu "do-${name}" do)
    (nu "cycle-${name}" cycle)

    (nu "run-${name}" run)
    (nu "spin-${name}" spin)
    (nu "close-${name}" close)
    # (nu "release-${name}" release)
  ] ++ dependencies; networking.firewall.allowedTCPPorts = [ 80 443 channel ];
}