123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- use path
- use builtin
- use str
- fn get-env {|name &default=$nil|
- if (has-env $name) {
- builtin:get-env $name
- } else {
- put $default
- }
- }
- fn get-hash {|@a|
- var dir = $pwd
- if (> (count $a) 0) {
- set dir = $a[0]
- }
- str:trim-right (echo $dir | sha256sum) "- "
- }
- fn state-type {|@a|
- var dir = $pwd
- if (> (count $a) 0) {
- set dir = $a[0]
- }
- if (path:is-regular $dir"/flake.nix") {
- put "nix"
- } elif (path:is-regular $dir"/shell.nix") {
- put "nix"
- } elif (path:is-regular $dir"/default.nix") {
- put "nix"
- } else {
- put $nil
- }
- }
- var state-dir = (get-env XDG_STATE_HOME &default=~/.local/state)/direlv
- var dir-stack = []
- var quiet = [
- AR
- AR_FOR_TARGET
- AS
- AS_FOR_TARGET
- CC
- CC_FOR_TARGET
- CXX
- CXX_FOR_TARGET
- LD
- LD_FOR_TARGET
- NM
- NM_FOR_TARGET
- RANLIB
- RANLIB_FOR_TARGET
- SIZE
- SIZE_FOR_TARGET
- STRINGS
- STRINGS_FOR_TARGET
- STRIP
- STRIP_FOR_TARGET
- READELF
- OBJCOPY
- OBJDUMP
- MACOSX_DEPLOYMENT_TARGET
- CONFIG_SHELL
- HOST_PATH
- ]
- var ignore = [
- # keep user variables
- HOME
- OLDPWD
- SHELL
- TEMP
- TEMPDIR
- TERM
- TMP
- TMPDIR
- TZ
- # purity-related envs
- NIX_ENFORCE_PURITY
- SOURCE_DATE_EPOCH
- ZERO_AR_DATE
- # nix build variables
- buildInputs
- buildPhase
- builder
- cmakeFlags
- configureFlags
- depsBuildBuild
- depsBuildBuildPropagated
- depsBuildTarget
- depsBuildTargetPropagated
- depsHostHost
- depsHostHostPropagated
- depsTargetTarget
- depsTargetTargetPropagated
- doCheck
- doInstallCheck
- dontAddDisableDepTrack
- mesonFlags
- name
- nativeBuildInputs
- out
- outputs
- patches
- phases
- preferLocalBuild
- propagatedBuildInputs
- propagatedNativeBuildInputs
- shell
- shellHook
- src
- stdenv
- strictDeps
- system
- ]
- var extend = [
- PATH
- XDG_DATA_DIRS
- ]
- fn diff-env {|env|
- each {|row|
- var key value = (all $row)
- put [$key (get-env $key)]
- } $env
- }
- fn print-change {|key new|
- if (has-value $quiet $key) {
- return
- }
- if (str:has-prefix $key "NIX_") {
- return
- }
- if $new {
- put +$key
- } else {
- put -$key
- }
- }
- fn apply-env {|env|
- each {|row|
- var key value = (all $row)
- if (eq $value $nil) {
- print-change $key $false
- unset-env $key
- } else {
- print-change $key $true
- set-env $key $value
- }
- } $env | compact
- }
- fn env-from-nix-flake {|state-file|
- var data = (from-json < $state-file)
- keys $data[variables] | each {|key|
- var v = $data[variables][$key]
- if (eq $v[type] "exported") {
- if (str:has-prefix $key "__") {
- continue
- } elif (has-value $ignore $key) {
- continue
- } elif (has-value $extend $key) {
- var extended = $v[value]
- if (eq $extended "") {
- continue
- }
- var existing = (get-env $key)
- if (not-eq $existing $nil) {
- set extended = $extended":"$existing
- }
- put [$key $extended]
- } else {
- put [$key $v[value]]
- }
- }
- }
- }
- fn push-dir {|type state-file path|
- var env-diff = $nil
- if (not-eq $state-file $nil) {
- var env = []
- if (eq $type "nix") {
- set @env = (env-from-nix-flake $state-file)
- }
- set @env-diff = (diff-env $env)
- edit:notify "Entered direlv "$path
- edit:notify (print (apply-env $env))
- }
- var entry = [&dir=$path &env-diff=$env-diff]
- set dir-stack = [ $entry $@dir-stack ]
- }
- fn pop-dir {
- var last = $dir-stack[0]
- if (not-eq $last[env-diff] $nil) {
- edit:notify "Exited direlv "$last[dir]
- edit:notify (print (apply-env $last[env-diff]))
- }
- set dir-stack = $dir-stack[1..]
- }
- fn current-dir {
- if (> (count $dir-stack) 0) {
- put $dir-stack[0][dir]
- } else {
- put $nil
- }
- }
- edit:add-var direlv~ {|@a|
- if (eq (count $a) 0) {
- echo "direlv <cache|clear>"
- return
- } elif (eq $a[0] "cache") {
- var type = (state-type)
- if (eq $type $nil) {
- fail "No flake.nix or shell.nix found"
- }
- mkdir -p $state-dir
- var hash = (get-hash)
- var state-file = $state-dir/$hash'-'$type
- if (eq $type "nix") {
- var args = [
- "--print-build-logs"
- "--profile"
- $state-file
- "--command"
- "true"
- ]
- if (path:is-regular "flake.nix") {
- # noop
- } elif (path:is-regular "shell.nix") {
- set args = [ "--file" "shell.nix" $@args ]
- } elif (path:is-regular "default.nix") {
- set args = [ "--file" "default.nix" $@args ]
- }
- # remove any extra links
- find $state-dir -name $hash'-*' -delete
- e:nix develop $@args
- }
- # if we're already in a direlv, unload first
- var dir = (current-dir)
- if (eq $dir $pwd) {
- pop-dir
- }
- push-dir $type $state-file $pwd
- } elif (eq $a[0] "clear") {
- var dir = (current-dir)
- if (not-eq $dir $nil) {
- var hash = (get-hash $dir)
- find $state-dir -name $hash'*' -delete
- pop-dir
- }
- }
- }
- fn on-chdir {|dir|
- while (> (count $dir-stack) 0) {
- if (eq $pwd $dir-stack[0][dir]) {
- return
- } elif (str:has-prefix $pwd $dir-stack[0][dir]) {
- break
- } else {
- pop-dir
- }
- }
- var last = "/"
- if (> (count $dir-stack) 0) {
- set last = $dir-stack[0][dir]
- }
- var current = $pwd
- var candidates = []
- while (and (str:has-prefix $current $last) (not-eq $current $last)) {
- set candidates = [ $current $@candidates ]
- if (eq $current "/") {
- # put this at the end so it can run against `/` once
- break
- }
- set current = (path:dir $current)
- }
- for candidate $candidates {
- var type = (state-type $candidate)
- if (not-eq $type $nil) {
- var hash = (get-hash $candidate)
- var state-file = $state-dir/$hash'-'$type
- if (path:is-regular $state-file &follow-symlink=$true) {
- push-dir $type $state-file $candidate
- } else {
- push-dir $type $nil $candidate
- }
- } else {
- push-dir "none" $nil $candidate
- }
- }
- }
- set after-chdir = [$on-chdir~ $@after-chdir]
|