{ lib, mkShell, writeShellScriptBin, buildEnv, rsync, lndir, rustup, rustc, cargo, rustc-unwrapped, withNonRustupSysroot ? true, rustLibSrc ? null, addToToolchain ? [ ], projectRoot, }: args: assert withNonRustupSysroot -> rustLibSrc != null; assert withNonRustupSysroot -> rustc-unwrapped != null; let ideaDir = "${projectRoot}/.idea/nix-rust"; sysrootDir = "${ideaDir}/sysroot"; rustupHome = "${ideaDir}/rustup-home"; fingerprintFile = "${ideaDir}/environment.fingerprint"; envFile = "${ideaDir}/shell-env"; toolchainName = "nix-toolchain"; tools = buildEnv { name = (args.name or "rr") + "-tools"; paths = addToToolchain; }; environmentFingerprint = builtins.hashString "sha256" (toString [ rustc cargo rustup (lib.optionals withNonRustupSysroot [ rustc-unwrapped rustLibSrc ]) tools ]); checkFingerprint = writeShellScriptBin "check-fingerprint" '' if [ -f "${fingerprintFile}" ] && [ -d ${sysrootDir} ]; then STORED_FINGERPRINT=$(cat "${fingerprintFile}") if [ "$STORED_FINGERPRINT" = "${environmentFingerprint}" ]; then echo "Environment is up to date at ${ideaDir}" exit 0 fi fi echo "Environment changed, recreating..." rm -rf ${ideaDir} && exit 1 ''; createSysrootNonRustup = writeShellScriptBin "create-sysroot" '' mkdir -p ${sysrootDir} ${lib.getExe lndir} ${rustc-unwrapped} ${sysrootDir} mkdir -p "${sysrootDir}/lib/rustlib/src/rust" rm -rf "${sysrootDir}/lib/rustlib/src/rust/library" ${lib.getExe rsync} -aq ${rustLibSrc}/ "${sysrootDir}/lib/rustlib/src/rust/library/" chmod -R u+w "${sysrootDir}/lib/rustlib/src/rust/library" ${lib.getExe lndir} ${cargo}/bin ${sysrootDir}/bin ${lib.getExe lndir} ${tools}/bin ${sysrootDir}/bin echo "${environmentFingerprint}" > "${fingerprintFile}" echo "Sysroot created at ${sysrootDir}" ''; createSysrootRustup = writeShellScriptBin "create-sysroot" '' mkdir -p ${sysrootDir} ${lndir}/bin/lndir ${rustc} ${sysrootDir} >/dev/null 2>&1 ${lndir}/bin/lndir ${cargo}/bin "${sysrootDir}/bin" >/dev/null 2>&1 ${lndir}/bin/lndir ${tools}/bin "${sysrootDir}/bin" >/dev/null 2>&1 echo "${environmentFingerprint}" > "${fingerprintFile}" echo "Sysroot created at ${sysrootDir}" ''; sourceEnv = '' if [ -f "${envFile}" ]; then set -a && source "${envFile}" && set +a fi ''; rustcWrapper = writeShellScriptBin "rustc" '' ${sourceEnv} if [ "$1" = "--print" ] && [ "$2" = "sysroot" ]; then echo ${sysrootDir} else exec ${rustup}/bin/rustc "$@" fi ''; rustupWrapper = writeShellScriptBin "rustup" '' ${sourceEnv} if [ "$1" = "component" ] && [ "$2" = "list" ]; then shift 2 exec ${./list-components.sh} ${sysrootDir} "$@" else exec -a "$0" ${rustup}/bin/rustup "$@" fi ''; createSysroot = if withNonRustupSysroot then createSysrootNonRustup else createSysrootRustup; createEnvironment = writeShellScriptBin "create-environment" '' ${lib.getExe checkFingerprint} && exit 0 mkdir -p .idea ${lib.getExe createSysroot} mkdir -p ${ideaDir}/bin ${lib.getExe lndir} ${rustup}/bin ${ideaDir}/bin && rm ${ideaDir}/bin/rustc ${ideaDir}/bin/rustup ${lib.getExe lndir} ${rustcWrapper}/bin ${ideaDir}/bin ${lib.getExe lndir} ${rustupWrapper}/bin ${ideaDir}/bin mkdir -p "$RUSTUP_HOME/toolchains" ${rustup}/bin/rustup toolchain link ${toolchainName} "${sysrootDir}" ${rustup}/bin/rustup default ${toolchainName} ''; in mkShell ( args // { packages = (args.packages or [ ]) ++ [ rustup ]; env.RUSTUP_HOME = rustupHome; shellHook = (args.shellHook or "") + '' ${lib.getExe createEnvironment} export -p | grep -vE '^declare -x (TMPDIR|TMP|TEMP|TEMPDIR)=' > "${envFile}" ''; } )