···121213131414::: info [Flake Generator](flake-generator.html) For Advanced Nix users
1515-If you already know Nix, and want to use pinned-version packages as inputs for your own Nix Flake
1616-or integrate with state-of-the-art Nix environments like
1515+If you already know Nix, and want to use pinned-version packages as inputs for your own Nix Flake
1616+or integrate with state-of-the-art Nix environments like
1717[devenv](https://devenv.sh/) or [devshell](https://github.com/numtide/devshell), `NixOS/nix-darwin/home-manager` or any other nix module class.
1818<b>See our [flake generator](flake-generator.html) service.</b>
1919:::
20202121#### Target Audience
22222323-As a Tools Version Manager, the pattern presented on this page can replace 90% of what tools like [asdf-vm](https://asdf-vm.com/) do,
2424-but with all the benefits you can get from Nix:
2525-All installable tools from Nixpkgs at your fingerprints, Reproducibility, Security Checksums, Sandboxed Builds, Remote Builders, Caching, etc.
2323+As a Tools Version Manager, the pattern presented on this page can replace 90% of what tools like [asdf-vm](https://asdf-vm.com/) do,
2424+but with all the benefits you can get from Nix:
2525+All installable tools from Nixpkgs at your fingerprints, Reproducibility, Security Checksums, Sandboxed Builds, Remote Builders, Caching, etc.
2626And of course, pinned version packages by `nix-versions`.
27272828-If you are new to Nix but have used other version managers like `nvm`, `rvm`, `asdf`, `mise` we want to provide you with an integrated toolset that lets you take advantage of Nix
2828+If you are new to Nix but have used other version managers like `nvm`, `rvm`, `asdf`, `mise` we want to provide you with an integrated toolset that lets you take advantage of Nix
2929without mandating you to learn the nix-language. By editing plain-text files and reusing your existing `.ruby-version`, `.node-version`, etc files, you can cover most of your needs.
30303131+::: info ⚡ Fast Track ⚡ 🏃 - The `use_nix_tools.bash` endpoint.
3232+3333+If you already have Nix and direnv installed, you can quickly get an environment ready in no time.
3434+Note that you don't even need `nix-versions` installed locally for this to work.
3535+Because the endpoint already resolves the nix-installales for you.
3636+(read bellow if you want to know more on how it works).
3737+3838+We recommend you to look at the downloaded script beforehand.
3939+You will notice a `use_nix_installables` function, that you can use independently of `nix-versions`.
4040+4141+```bash
4242+# Place this on your .envrc
4343+source_url "https://nix-versions.alwaysdata.net/use_nix_tools.bash/go/ruby" HASH
4444+```
4545+4646+Where `HASH` can be obtained with:
4747+4848+```bash
4949+direnv fetchurl "https://nix-versions.alwaysdata.net/use_nix_tools.bash/go/ruby"
5050+```
5151+5252+You can obtian package updates by doing `direnv reload`.
5353+:::
5454+3155## How it works
32563357By playing well with others. Following the UNIX philosophy of doing just ONE thing (listing package versions) and produce plain-text output that can be used by other programs to become part of something bigger.
···48724973#### Reading package specs from a plain-text file
50745151-Instead of giving package specs as command line arguments you can use the `--read` (short `-r`) [option](../getting-started/cli-help.html) for reading them from a file.
7575+Instead of giving package specs as command line arguments you can use the `--read` (short `-r`) [option](../getting-started/cli-help.html) for reading them from a file.
52765377Name of the file is not special to `nix-versions`, but we use the convention of having a `.nix_tools` file.
5478···100124will install a function that all your projects can use to load their respective environment.
101125102126```shell
103103-# This is $HOME/.config/direnv/lib/use_nix_tools.bash
104104-function use_nix_tools() {
105105- tools_file="${1:-.nix_tools}" # defaults to .nix_tools file unless given explicitly
106106- watch_file $tools_file
107107- direnv_load nix shell $(nix-versions -ir $tools_file) -c $direnv dump
108108-}
127127+mkdir -p ~/.config/direnv/lib
128128+# You can always inspect the downloaded function before installing it
129129+curl "https://nix-versions.alwaysdata.net/use_nix_tools.bash" -o ~/.config/direnv/lib/use_nix_tools.bash
109130```
110131111132Then, on your project directory, besides your `.nix_tools` file, create an `.envrc` file that will be
···116137use nix_tools
117138```
118139119119-And you are set, just `direnv allow` and enjoy using your tools.
140140+::: tip Arguments to the `use_nix_tools` function.
141141+If given no arguments, a `$PWD/.nix_tools` file will be read. But you can provide any
142142+other file with the same format as described above or any package-spec as expected by the `nix-versions` cli.
143143+:::
144144+145145+And you are set!, just `direnv allow` and enjoy using your tools.
120146121147122148## More advanced environments.
123149124150The Nix ecosystem has much more advanced development environments that those produced by `nix shell`.
125151A couple of them are [devenv](https://devenv.sh/) and [devshell](https://github.com/numtide/devshell),
126126-that provide more advanced features than simply loading environment variables.
152152+that provide more advanced features than simply loading environment variables.
127153128154They have different features depending on your needs, but they can do process management, services, deployment of containers, git workflow hooks, and much more. Be sure to read their webpages for more info.
129155
+57-9
web/main.go
···55 "bytes"
66 "context"
77 "crypto/sha256"
88+ _ "embed"
89 "encoding/base64"
910 "encoding/hex"
1011 "fmt"
1112 "io"
1213 "net/http"
1314 "os"
1515+ "slices"
1416 "strings"
15171618 "golang.org/x/sync/errgroup"
···1921 "github.com/vic/ntv/packages/search"
2022 "github.com/vic/ntv/packages/search_spec"
2123)
2424+2525+//go:embed use_nix_tools.bash
2626+var use_nix_tools_bash string
22272328func main() {
2929+ http.HandleFunc("/use_nix_tools.bash", HandleUseNixToolsBash)
3030+ http.HandleFunc("/use_nix_tools.bash/", HandleUseNixToolsBash)
2431 http.HandleFunc("/flake.nix/", HandleFlakeNix)
2532 http.HandleFunc("/flake.zip/", HandleFlakeZip)
2633 http.HandleFunc("/default.nix/", HandleDefaultNix)
···3643 http.ListenAndServe(addr, nil)
3744}
38454646+func getParts(path string) []string {
4747+ parts := strings.Split(path, "/")
4848+ parts = slices.DeleteFunc(parts, func(p string) bool {
4949+ return len(strings.TrimSpace(p)) == 0
5050+ })
5151+ return parts
5252+}
5353+5454+func HandleUseNixToolsBash(w http.ResponseWriter, r *http.Request) {
5555+ werr := func(err error) {
5656+ http.Error(w, err.Error(), http.StatusInternalServerError)
5757+ }
5858+ path := strings.TrimPrefix(r.URL.Path, "/use_nix_tools.bash")
5959+ parts := getParts(path)
6060+ fmt.Println("Gen use_nix_tools_bash: ", parts)
6161+ installables := make([]string, 0)
6262+6363+ if len(parts) > 0 {
6464+ fmt.Println("Searching ", parts)
6565+ results, err := searchSpecs(parts)
6666+ if err != nil {
6767+ werr(err)
6868+ return
6969+ }
7070+ for _, res := range results {
7171+ installables = append(installables, res.Installable(res.Selected))
7272+ }
7373+ }
7474+7575+ w.Header().Set("Content-Type", "application/x-shellscript")
7676+ w.Header().Set("Content-Disposition", "attachment; filename=use_nix_tools.bash")
7777+ w.Header().Set("Cache-Control", "no-cache")
7878+ w.Header().Set("Pragma", "no-cache")
7979+ w.Header().Set("Expires", "0")
8080+ fmt.Fprint(w, use_nix_tools_bash)
8181+8282+ if len(installables) > 0 {
8383+ fmt.Fprintf(w, "\nuse nix_installables %s\n", strings.Join(installables, " "))
8484+ }
8585+}
8686+3987func searchSpecs(args []string) (search.PackageSearchResults, error) {
4088 backend := search_spec.VersionsBackend{
4189 NixHub: &search_spec.Unit{},
···161209 }
162210 outs := `
163211 nixpkgs = pkgs.lib.mapAttrs (name: tool:
164164- let
165165- archive = pkgs.fetchurl {
212212+ let
213213+ archive = pkgs.fetchurl {
166214 name = "${name}-${tool.version}-nixpkgs.tar.gz";
167215 url = tool.url;
168216 hash = tool.hash;
169217 };
170218 # since our sri was computed on the tarball, we need to unpack it
171171- # we could use fetchzip, but we'd have to extract the tarball on
219219+ # we could use fetchzip, but we'd have to extract the tarball on
172220 # the server to compute recursive sri (which we wont do).
173221 unpacked = pkgs.stdenvNoCC.mkDerivation {
174222 name = "${name}-${tool.version}-nixpkgs";
···181229 in unpacked
182230 ) tools;
183231 packages = pkgs.lib.mapAttrs (name: tool:
184184- let
232232+ let
185233 pkgs' = import nixpkgs.${name} { inherit (pkgs) system config; };
186234 path = pkgs.lib.splitString "." tool.attrPath;
187235 pkg = pkgs.lib.getAttrFromPath path pkgs';
188236 in pkg
189237 ) tools;
190190- pkgsEnv = pkgs.buildEnv { name = "tools"; paths = pkgs.lib.attrValues packages; };
238238+ pkgsEnv = pkgs.buildEnv { name = "tools"; paths = pkgs.lib.attrValues packages; };
191239 devShell = pkgs.mkShell { buildInputs = [ pkgsEnv ]; };
192240 `
193241 w(0, strings.ReplaceAll(outs, "\t", " "))
···201249 http.Error(w, err.Error(), http.StatusInternalServerError)
202250 }
203251 path := strings.TrimPrefix(r.URL.Path, "/default.nix/")
204204- parts := strings.Split(path, "/")
252252+ parts := getParts(path)
205253 fmt.Println("Gen default.nix: ", parts)
206254207255 nix, err := renderDefaultNix(parts)
···223271 http.Error(w, err.Error(), http.StatusInternalServerError)
224272 }
225273 path := strings.TrimPrefix(r.URL.Path, "/flake.nix/")
226226- parts := strings.Split(path, "/")
274274+ parts := getParts(path)
227275 fmt.Println("Gen flake.nix: ", parts)
228276229277 flake, err := renderFlake(parts)
···245293 http.Error(w, err.Error(), http.StatusInternalServerError)
246294 }
247295 path := strings.TrimPrefix(r.URL.Path, "/default.zip/")
248248- parts := strings.Split(path, "/")
296296+ parts := getParts(path)
249297 fmt.Println("Gen default.zip: ", parts)
250298251299 nix, err := renderDefaultNix(parts)
···274322 http.Error(w, err.Error(), http.StatusInternalServerError)
275323 }
276324 path := strings.TrimPrefix(r.URL.Path, "/flake.zip/")
277277- parts := strings.Split(path, "/")
325325+ parts := getParts(path)
278326 fmt.Println("Gen flake.zip: ", parts)
279327280328 flake, err := renderFlake(parts)
+21
web/use_nix_tools.bash
···11+function use_nix_installables {
22+ direnv_load nix shell "${@}" -c $direnv dump
33+}
44+55+function use_nix_tools {
66+ declare -a args
77+ if test -z "${1:-}"; then
88+ watch_file "$PWD/.nix_tools"
99+ args+=("--read" "${PWD}/.nix_tools")
1010+ fi
1111+ while test -n "$1"; do
1212+ if test -f "$1"; then
1313+ watch_file "$1"
1414+ args+=("--read" $1)
1515+ else
1616+ args+=("$1")
1717+ fi
1818+ shift
1919+ done
2020+ use_nix_installables $(nix-versions --installable "${args[@]}")
2121+}