# Adapted from https://github.com/edolstra/flake-compat/blob/master/default.nix # # This version only gives back the inputs. In that mode, flake becomes little # more than a niv replacement. { src ? ./. }: let lockFilePath = src + "/flake.lock"; lockFile = builtins.fromJSON (builtins.readFile lockFilePath); # Emulate builtins.fetchTree # # TODO: only implement polyfill if the builtin doesn't exist? fetchTree = info: if info.type == "github" then { outPath = fetchTarball { url = "https://api.${info.host or "github.com"}/repos/${info.owner}/${info.repo}/tarball/${info.rev}"; sha256 = info.narHash; }; rev = info.rev; shortRev = builtins.substring 0 7 info.rev; lastModified = info.lastModified; narHash = info.narHash; } else if info.type == "git" then { outPath = builtins.fetchGit ({ url = info.url; sha256 = info.narHash; } // (if info ? rev then { inherit (info) rev; } else { }) // (if info ? ref then { inherit (info) ref; } else { }) ); lastModified = info.lastModified; narHash = info.narHash; } // (if info ? rev then { rev = info.rev; shortRev = builtins.substring 0 7 info.rev; } else { }) else if info.type == "path" then { outPath = builtins.path { path = info.path; }; narHash = info.narHash; } else if info.type == "tarball" then { outPath = fetchTarball { url = info.url; sha256 = info.narHash; }; narHash = info.narHash; } else if info.type == "gitlab" then { inherit (info) rev narHash lastModified; outPath = fetchTarball { url = "https://${info.host or "gitlab.com"}/api/v4/projects/${info.owner}%2F${info.repo}/repository/archive.tar.gz?sha=${info.rev}"; sha256 = info.narHash; }; shortRev = builtins.substring 0 7 info.rev; } else # FIXME: add Mercurial, tarball inputs. throw "flake input has unsupported input type '${info.type}'"; allNodes = builtins.mapAttrs (key: node: let sourceInfo = if key == lockFile.root then { } else fetchTree (node.info or { } // removeAttrs node.locked [ "dir" ]); inputs = builtins.mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}) (node.inputs or { }); # Resolve a input spec into a node name. An input spec is # either a node name, or a 'follows' path from the root # node. resolveInput = inputSpec: if builtins.isList inputSpec then getInputByPath lockFile.root inputSpec else inputSpec; # Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the # root node, returning the final node. getInputByPath = nodeName: path: if path == [ ] then nodeName else getInputByPath # Since this could be a 'follows' input, call resolveInput. (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path}) (builtins.tail path); result = sourceInfo // { inherit inputs; inherit sourceInfo; }; in if node.flake or true then result else sourceInfo ) lockFile.nodes; result = if lockFile.version >= 5 && lockFile.version <= 7 then allNodes.${lockFile.root}.inputs else throw "lock file '${lockFilePath}' has unsupported version ${toString lockFile.version}"; in result