> I'd almost rather build a container and work within that than write nix to get this functionality
If you're happy writing shell commands/scripts, then just stick them in the following template:
with import <nixpkgs> {};
runCommand "name-of-your-thing"
{
someEnvVar = "some value";
someOtherEnvVar = "some other value";
buildInputs = [ programs you want to run ]; # e.g. see search.nixos.org/packages
}
''
run any bash code you like here
just make sure the file/folder you want to output
uses the env var "$out" as its path
''
You can always defunctionalise some particular code, to get a more static/declarative DSL. That's already quite a common pattern in Nix, where we can write Nix functions that act as interpreters for some more "declarative" DSL; indeed, many of the "foo2nix" utilities are just interpreters, written in Nix, for some third-party DSL; e.g. the "callCabal2nix" function in Nixpkgs can read the .cabal file of a Haskell project, and there are many other examples. The `builtins.readJSON` function is a particularly useful building block for such functions.
I don't think it's a good idea to defunctionalise the Nix language itself, since the result would either be too inflexibile or incredibly complex. Keep in mind that the Nix language has no idea what a shell is, or any concept of "package", etc. yet it's flexible enough to write functions like `runCommand`, which is used in the example above.
Also, it's reasonable to argue that Nix is already declarative, since that's what the `.drv` files are for! However, they're so tedious to work with that it's preferable to generate them using a "proper" language like the Nix expression language (or Guile Scheme if you're using Guix)!
If you're happy writing shell commands/scripts, then just stick them in the following template: