• Operand
  • # (b)ring mi - belles.

gram:build

> ./nixos/gram/elixir.nix

Lenses
(coming soon!)


{ channel, base, domain, codebase, name, ... }:
  # run_command ? "elixir --erl '-detached' -S mix phx.server",
{ pkgs, ... }:
let
  command = "${nd} _build/prod/rel/${name}/bin/${name}";
  cron = "(bash -c 'date -Is' | str trim)";
  place = "([ /root ${name} run ] | path join)";
  nd = "cd ${place}; nix develop --command";
  nd-place = node: "cd ${place}; cd ${node}; nix develop --command";

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

  run = with measures; nu "run-${name}" ''
    ${clone}
    ${close}
    ${load}
    ${release}
    ${cycle}
    ${help}
  '';

  measures = {
    clone = ''
      let cloc = ${cron}
      # securely lock in hash here ----v
      let source = ( [ ~ ${name} $cloc '*-source' ] | path join | path expand );
      mkdir ([ ~ ${name} ] | path join | path expand)
      ${pkgs.rsync}/bin/rsync -av ${codebase} ($source | path dirname)
      let node = (ls ($source | into glob)).name.0
      let share = [ / root share gram ${name} share ] | path join
      try { rm ${place} }; ln -s $node ${place}
      ln -s $share ([ / root ${name} run share ] | path join)
    '';

    load = ''
      load-env (
        cat ([$env.HOME ${name}.call] | path join) | lines | split column '=' |
        transpose --ignore-titles -r -d | into record
      )
    '';

    release = ''
      cd ${place}
      ${nd} mix deps.get --only prod
      ${nd} mix compile
      try { ${nd-place "assets"} yarn }
      ${nd} mix assets.deploy
      ${nd} mix release
    '';

    cycle = ''
      ${measures.close}
      ${do}/bin/do-${name} daemon
    '';

    close = "try { ${close_channel channel} }"; # ${measures.load}

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

    help = ''
      echo ""
      echo "Run more ops, using:"
      echo "  do-${name} <call>\\n)"
      echo ""
      echo "Possible ops:"
      echo "  > do-${name} start       # Begin in local session"
      echo "  > do-${name} start_iex   # local session command line"
      echo "  > do-${name} daemon      # background process, handled by scheduler
      echo "  > do-${name} daemon_iex  # local debugger paired alongside a background process"
      echo "  > do-${name} eval [EXPR] # Run a command in a compiled and non-running codespace"
      echo "  > do-${name} rpc [EXPR]  # Run a command in a running relay"
      echo "  > do-${name} remote      # Open a shell inside a running relay"
      echo "  > do-${name} restart     # Relaunches a relay"
      echo "  > do-${name} stop        # Drops a relay"
      echo "  > do-${name} pid         # Display relay's process number"
      echo "  > do-${name} version     # Display release name and grade-number"
    '';
  };

  # mix = nu "mix-${name}" ''
  #   ${measures.load}
  #   ${nd} mix ...($call)
  # '';

  # ${command} daemon #_iex
  # ${measures.load}
  # try { ${close_channel channel} }
  # (cd ~/${name}/run; ${nd} ${run_command})

    # ( cd ~/${name}/run/; ${nd} mix phx.gen.release)
    # ( cd ~/${name}/run/; print $env)

  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 {
  # system.userActivationScripts."run-${name}".text = run;

  environment.systemPackages = with pkgs; [
    run do
    (nu "close-${name}" measures.close)
    (nu "cycle-${name}" measures.cycle)
    (nu "load-${name}" measures.load)
    (nu "release-${name}" measures.release)
  ];
    # inotify-tools

  networking.firewall.allowedTCPPorts = [ 80 443 channel ];

  services.caddy = { enable = true;
    virtualHosts.${domain}.extraConfig = ''
    reverse_proxy 127.0.0.1:${toString channel}
    log {
      output file /var/lib/caddy/${name}.log {
        roll_size     200MiB
        roll_local_time
        roll_keep     1440
        roll_keep_for 1440d
      }
    }
    '';
  };

  services.postgresql = {
    enable = true; enableTCPIP = true; settings.port = 5432;
    authentication = pkgs.lib.mkOverride 10 ''
    local all all trust
    host  all all 127.0.0.1/32   trust
    host  all all ::1/128        trust
    '';
  };

  systemd.services."${name}@elixir" = { enable = false;
    description = "${name}, running locally on :${toString channel} and securely proxied on ${domain}";
    wantedBy = ["multi-user.target"];
    unitConfig = { After = "local-fs.target"; Wants = "local-fs.target"; };

    environment = {
      PHX_HOST = domain; DATABASE_URL = "postgres://postgres@127.0.0.1:5432/${name}";
      PORT = toString channel; MIX_ENV = "prod"; PHX_SERVER = "y";
      HOME = "/root"; NO_VHOST = "0";
    };

# environment.PATH = lib.mkForce "/run/current-system/sw/bin/";
    serviceConfig = { Type = "forking"; KillMode = "mixed"; TimeoutSec = 0;
      ExecStart = "${run}/bin/run-${name}"; };
  };
}