open Fnm; module ExportShellVarCmdGetters = { type exportCmdGetter = { getPathCmd: string => string, getMultiShellPathCmd: string => string, getFnmDirCmd: string => string, getNodeDistMirrorCmd: string => string, getLogLevelCmd: string => string, }; let posixExportCmdGetter: exportCmdGetter = { getPathCmd: path => Printf.sprintf("export PATH=%s/bin:$PATH", path), getMultiShellPathCmd: path => Printf.sprintf("export %s=%s", Config.FNM_MULTISHELL_PATH.name, path), getFnmDirCmd: fnmDir => Printf.sprintf("export %s=%s", Config.FNM_DIR.name, fnmDir), getNodeDistMirrorCmd: nodeDistMirror => Printf.sprintf( "export %s=%s", Config.FNM_NODE_DIST_MIRROR.name, nodeDistMirror, ), getLogLevelCmd: logLevel => Printf.sprintf("export %s=%s", Config.FNM_LOGLEVEL.name, logLevel), }; let fishExportCmdGetter: exportCmdGetter = { getPathCmd: path => Printf.sprintf("set -gx PATH %s/bin $PATH;", path), getMultiShellPathCmd: path => Printf.sprintf("set -gx %s %s;", Config.FNM_MULTISHELL_PATH.name, path), getFnmDirCmd: fnmDir => Printf.sprintf("set -gx %s %s;", Config.FNM_DIR.name, fnmDir), getNodeDistMirrorCmd: nodeDistMirror => Printf.sprintf( "set -gx %s %s", Config.FNM_NODE_DIST_MIRROR.name, nodeDistMirror, ), getLogLevelCmd: logLevel => Printf.sprintf("set -gx %s %s", Config.FNM_LOGLEVEL.name, logLevel), }; }; let symlinkExists = path => try%lwt(Lwt_unix.lstat(path) |> Lwt.map(_ => true)) { | _ => Lwt.return(false) }; let rec makeTemporarySymlink = () => { let suggestedName = Filename.concat( Filename.get_temp_dir_name(), "fnm-shell-" ++ (Random.int32(9999999 |> Int32.of_int) |> Int32.to_string), ); let%lwt exists = symlinkExists(suggestedName); if (exists) { let%lwt suggestedName = makeTemporarySymlink(); Lwt.return(suggestedName); } else { let%lwt _ = Lwt_unix.symlink(Directories.defaultVersion, suggestedName); Lwt.return(suggestedName); }; }; let printUseOnCd = (~shell) => switch (shell) { | System.Shell.Bash => {| __fnmcd () { cd "$@" if [[ -f .node-version && -r .node-version ]]; then echo "fnm: Found .node-version" fnm use elif [[ -f .nvmrc && -r .nvmrc ]]; then echo "fnm: Found .nvmrc" fnm use fi } alias cd=__fnmcd |} | Fish => {| function _fnm_autoload_hook --on-variable PWD --description 'Change Node version on directory change' status --is-command-substitution; and return if test -f .node-version echo "fnm: Found .node-version" fnm use else if test -f .nvmrc echo "fnm: Found .nvmrc" fnm use end end _fnm_autoload_hook |} | Zsh => {| autoload -U add-zsh-hook _fnm_autoload_hook () { if [[ -f .node-version && -r .node-version ]]; then echo "fnm: Found .node-version" fnm use elif [[ -f .nvmrc && -r .nvmrc ]]; then echo "fnm: Found .nvmrc" fnm use fi } add-zsh-hook chpwd _fnm_autoload_hook \ && _fnm_autoload_hook |} }; let run = (~forceShell, ~multishell, ~nodeDistMirror, ~fnmDir, ~useOnCd, ~logLevel) => { open System.Shell; let%lwt shell = switch (forceShell) { | None => switch%lwt (System.Shell.infer()) { | None => Lwt.return(Bash) | Some(shell) => Lwt.return(shell) } | Some(shell) => Lwt.return(shell) }; Random.self_init(); let%lwt path = multishell ? makeTemporarySymlink() : Lwt.return(Directories.globalCurrentVersion); let exportCmdGetter = shell === Fish ? ExportShellVarCmdGetters.fishExportCmdGetter : ExportShellVarCmdGetters.posixExportCmdGetter; exportCmdGetter.getPathCmd(path) |> Console.log; exportCmdGetter.getMultiShellPathCmd(path) |> Console.log; exportCmdGetter.getFnmDirCmd(fnmDir) |> Console.log; exportCmdGetter.getNodeDistMirrorCmd(nodeDistMirror) |> Console.log; Fnm.LogLevel.toString(logLevel) |> exportCmdGetter.getLogLevelCmd |> Console.log; if (useOnCd) { printUseOnCd(~shell) |> Console.log; }; Lwt.return_ok(); };