Search nix packages versions - and minimalist devshell and version manager built on nix - Flake generator for version pinned packages.

Add direnv endpoint

+119 -24
+41 -15
docs/tools-version-manager.md
··· 12 12 13 13 14 14 ::: info [Flake Generator](flake-generator.html) For Advanced Nix users 15 - If you already know Nix, and want to use pinned-version packages as inputs for your own Nix Flake 16 - or integrate with state-of-the-art Nix environments like 15 + If you already know Nix, and want to use pinned-version packages as inputs for your own Nix Flake 16 + or integrate with state-of-the-art Nix environments like 17 17 [devenv](https://devenv.sh/) or [devshell](https://github.com/numtide/devshell), `NixOS/nix-darwin/home-manager` or any other nix module class. 18 18 <b>See our [flake generator](flake-generator.html) service.</b> 19 19 ::: 20 20 21 21 #### Target Audience 22 22 23 - 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, 24 - but with all the benefits you can get from Nix: 25 - All installable tools from Nixpkgs at your fingerprints, Reproducibility, Security Checksums, Sandboxed Builds, Remote Builders, Caching, etc. 23 + 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, 24 + but with all the benefits you can get from Nix: 25 + All installable tools from Nixpkgs at your fingerprints, Reproducibility, Security Checksums, Sandboxed Builds, Remote Builders, Caching, etc. 26 26 And of course, pinned version packages by `nix-versions`. 27 27 28 - 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 28 + 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 29 29 without 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. 30 30 31 + ::: info ⚡ Fast Track ⚡ 🏃 - The `use_nix_tools.bash` endpoint. 32 + 33 + If you already have Nix and direnv installed, you can quickly get an environment ready in no time. 34 + Note that you don't even need `nix-versions` installed locally for this to work. 35 + Because the endpoint already resolves the nix-installales for you. 36 + (read bellow if you want to know more on how it works). 37 + 38 + We recommend you to look at the downloaded script beforehand. 39 + You will notice a `use_nix_installables` function, that you can use independently of `nix-versions`. 40 + 41 + ```bash 42 + # Place this on your .envrc 43 + source_url "https://nix-versions.alwaysdata.net/use_nix_tools.bash/go/ruby" HASH 44 + ``` 45 + 46 + Where `HASH` can be obtained with: 47 + 48 + ```bash 49 + direnv fetchurl "https://nix-versions.alwaysdata.net/use_nix_tools.bash/go/ruby" 50 + ``` 51 + 52 + You can obtian package updates by doing `direnv reload`. 53 + ::: 54 + 31 55 ## How it works 32 56 33 57 By 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. ··· 48 72 49 73 #### Reading package specs from a plain-text file 50 74 51 - 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. 75 + 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. 52 76 53 77 Name of the file is not special to `nix-versions`, but we use the convention of having a `.nix_tools` file. 54 78 ··· 100 124 will install a function that all your projects can use to load their respective environment. 101 125 102 126 ```shell 103 - # This is $HOME/.config/direnv/lib/use_nix_tools.bash 104 - function use_nix_tools() { 105 - tools_file="${1:-.nix_tools}" # defaults to .nix_tools file unless given explicitly 106 - watch_file $tools_file 107 - direnv_load nix shell $(nix-versions -ir $tools_file) -c $direnv dump 108 - } 127 + mkdir -p ~/.config/direnv/lib 128 + # You can always inspect the downloaded function before installing it 129 + curl "https://nix-versions.alwaysdata.net/use_nix_tools.bash" -o ~/.config/direnv/lib/use_nix_tools.bash 109 130 ``` 110 131 111 132 Then, on your project directory, besides your `.nix_tools` file, create an `.envrc` file that will be ··· 116 137 use nix_tools 117 138 ``` 118 139 119 - And you are set, just `direnv allow` and enjoy using your tools. 140 + ::: tip Arguments to the `use_nix_tools` function. 141 + If given no arguments, a `$PWD/.nix_tools` file will be read. But you can provide any 142 + other file with the same format as described above or any package-spec as expected by the `nix-versions` cli. 143 + ::: 144 + 145 + And you are set!, just `direnv allow` and enjoy using your tools. 120 146 121 147 122 148 ## More advanced environments. 123 149 124 150 The Nix ecosystem has much more advanced development environments that those produced by `nix shell`. 125 151 A couple of them are [devenv](https://devenv.sh/) and [devshell](https://github.com/numtide/devshell), 126 - that provide more advanced features than simply loading environment variables. 152 + that provide more advanced features than simply loading environment variables. 127 153 128 154 They 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. 129 155
+57 -9
web/main.go
··· 5 5 "bytes" 6 6 "context" 7 7 "crypto/sha256" 8 + _ "embed" 8 9 "encoding/base64" 9 10 "encoding/hex" 10 11 "fmt" 11 12 "io" 12 13 "net/http" 13 14 "os" 15 + "slices" 14 16 "strings" 15 17 16 18 "golang.org/x/sync/errgroup" ··· 19 21 "github.com/vic/ntv/packages/search" 20 22 "github.com/vic/ntv/packages/search_spec" 21 23 ) 24 + 25 + //go:embed use_nix_tools.bash 26 + var use_nix_tools_bash string 22 27 23 28 func main() { 29 + http.HandleFunc("/use_nix_tools.bash", HandleUseNixToolsBash) 30 + http.HandleFunc("/use_nix_tools.bash/", HandleUseNixToolsBash) 24 31 http.HandleFunc("/flake.nix/", HandleFlakeNix) 25 32 http.HandleFunc("/flake.zip/", HandleFlakeZip) 26 33 http.HandleFunc("/default.nix/", HandleDefaultNix) ··· 36 43 http.ListenAndServe(addr, nil) 37 44 } 38 45 46 + func getParts(path string) []string { 47 + parts := strings.Split(path, "/") 48 + parts = slices.DeleteFunc(parts, func(p string) bool { 49 + return len(strings.TrimSpace(p)) == 0 50 + }) 51 + return parts 52 + } 53 + 54 + func HandleUseNixToolsBash(w http.ResponseWriter, r *http.Request) { 55 + werr := func(err error) { 56 + http.Error(w, err.Error(), http.StatusInternalServerError) 57 + } 58 + path := strings.TrimPrefix(r.URL.Path, "/use_nix_tools.bash") 59 + parts := getParts(path) 60 + fmt.Println("Gen use_nix_tools_bash: ", parts) 61 + installables := make([]string, 0) 62 + 63 + if len(parts) > 0 { 64 + fmt.Println("Searching ", parts) 65 + results, err := searchSpecs(parts) 66 + if err != nil { 67 + werr(err) 68 + return 69 + } 70 + for _, res := range results { 71 + installables = append(installables, res.Installable(res.Selected)) 72 + } 73 + } 74 + 75 + w.Header().Set("Content-Type", "application/x-shellscript") 76 + w.Header().Set("Content-Disposition", "attachment; filename=use_nix_tools.bash") 77 + w.Header().Set("Cache-Control", "no-cache") 78 + w.Header().Set("Pragma", "no-cache") 79 + w.Header().Set("Expires", "0") 80 + fmt.Fprint(w, use_nix_tools_bash) 81 + 82 + if len(installables) > 0 { 83 + fmt.Fprintf(w, "\nuse nix_installables %s\n", strings.Join(installables, " ")) 84 + } 85 + } 86 + 39 87 func searchSpecs(args []string) (search.PackageSearchResults, error) { 40 88 backend := search_spec.VersionsBackend{ 41 89 NixHub: &search_spec.Unit{}, ··· 161 209 } 162 210 outs := ` 163 211 nixpkgs = pkgs.lib.mapAttrs (name: tool: 164 - let 165 - archive = pkgs.fetchurl { 212 + let 213 + archive = pkgs.fetchurl { 166 214 name = "${name}-${tool.version}-nixpkgs.tar.gz"; 167 215 url = tool.url; 168 216 hash = tool.hash; 169 217 }; 170 218 # since our sri was computed on the tarball, we need to unpack it 171 - # we could use fetchzip, but we'd have to extract the tarball on 219 + # we could use fetchzip, but we'd have to extract the tarball on 172 220 # the server to compute recursive sri (which we wont do). 173 221 unpacked = pkgs.stdenvNoCC.mkDerivation { 174 222 name = "${name}-${tool.version}-nixpkgs"; ··· 181 229 in unpacked 182 230 ) tools; 183 231 packages = pkgs.lib.mapAttrs (name: tool: 184 - let 232 + let 185 233 pkgs' = import nixpkgs.${name} { inherit (pkgs) system config; }; 186 234 path = pkgs.lib.splitString "." tool.attrPath; 187 235 pkg = pkgs.lib.getAttrFromPath path pkgs'; 188 236 in pkg 189 237 ) tools; 190 - pkgsEnv = pkgs.buildEnv { name = "tools"; paths = pkgs.lib.attrValues packages; }; 238 + pkgsEnv = pkgs.buildEnv { name = "tools"; paths = pkgs.lib.attrValues packages; }; 191 239 devShell = pkgs.mkShell { buildInputs = [ pkgsEnv ]; }; 192 240 ` 193 241 w(0, strings.ReplaceAll(outs, "\t", " ")) ··· 201 249 http.Error(w, err.Error(), http.StatusInternalServerError) 202 250 } 203 251 path := strings.TrimPrefix(r.URL.Path, "/default.nix/") 204 - parts := strings.Split(path, "/") 252 + parts := getParts(path) 205 253 fmt.Println("Gen default.nix: ", parts) 206 254 207 255 nix, err := renderDefaultNix(parts) ··· 223 271 http.Error(w, err.Error(), http.StatusInternalServerError) 224 272 } 225 273 path := strings.TrimPrefix(r.URL.Path, "/flake.nix/") 226 - parts := strings.Split(path, "/") 274 + parts := getParts(path) 227 275 fmt.Println("Gen flake.nix: ", parts) 228 276 229 277 flake, err := renderFlake(parts) ··· 245 293 http.Error(w, err.Error(), http.StatusInternalServerError) 246 294 } 247 295 path := strings.TrimPrefix(r.URL.Path, "/default.zip/") 248 - parts := strings.Split(path, "/") 296 + parts := getParts(path) 249 297 fmt.Println("Gen default.zip: ", parts) 250 298 251 299 nix, err := renderDefaultNix(parts) ··· 274 322 http.Error(w, err.Error(), http.StatusInternalServerError) 275 323 } 276 324 path := strings.TrimPrefix(r.URL.Path, "/flake.zip/") 277 - parts := strings.Split(path, "/") 325 + parts := getParts(path) 278 326 fmt.Println("Gen flake.zip: ", parts) 279 327 280 328 flake, err := renderFlake(parts)
+21
web/use_nix_tools.bash
··· 1 + function use_nix_installables { 2 + direnv_load nix shell "${@}" -c $direnv dump 3 + } 4 + 5 + function use_nix_tools { 6 + declare -a args 7 + if test -z "${1:-}"; then 8 + watch_file "$PWD/.nix_tools" 9 + args+=("--read" "${PWD}/.nix_tools") 10 + fi 11 + while test -n "$1"; do 12 + if test -f "$1"; then 13 + watch_file "$1" 14 + args+=("--read" $1) 15 + else 16 + args+=("$1") 17 + fi 18 + shift 19 + done 20 + use_nix_installables $(nix-versions --installable "${args[@]}") 21 + }