{ lib , callPackage , fetchurl , fetchgit , runCommand }: { # The source directory of the package. src # The package subdirectory within src. # Useful if the package references sibling packages with relative paths. , packageRoot ? "." # The pubspec.lock file, in attribute set form. , pubspecLock # Hashes for Git dependencies. # Pub does not record these itself, so they must be manually provided. , gitHashes ? { } # Functions to generate SDK package sources. # The function names should match the SDK names, and the package name is given as an argument. , sdkSourceBuilders ? { } # Functions that create custom package source derivations. # # The function names should match the package names, and the package version, # source, and source files are given in an attribute set argument. # # The passthru of the source derivation should be propagated. , customSourceBuilders ? { } }: let dependencyVersions = builtins.mapAttrs (name: details: details.version) pubspecLock.packages; dependencyTypes = { "direct main" = "main"; "direct dev" = "dev"; "direct overridden" = "overridden"; "transitive" = "transitive"; }; dependencies = lib.foldlAttrs (dependencies: name: details: dependencies // { ${dependencyTypes.${details.dependency}} = dependencies.${dependencyTypes.${details.dependency}} ++ [ name ]; }) (lib.genAttrs (builtins.attrValues dependencyTypes) (dependencyType: [ ])) pubspecLock.packages; # fetchTarball fails with "tarball contains an unexpected number of top-level files". This is a workaround. # https://discourse.nixos.org/t/fetchtarball-with-multiple-top-level-directories-fails/20556 mkHostedDependencySource = name: details: let archive = fetchurl { name = "pub-${name}-${details.version}.tar.gz"; url = "${details.description.url}/packages/${details.description.name}/versions/${details.version}.tar.gz"; sha256 = details.description.sha256; }; in runCommand "pub-${name}-${details.version}" { passthru.packageRoot = "."; } '' mkdir -p "$out" tar xf '${archive}' -C "$out" ''; mkGitDependencySource = name: details: (fetchgit { name = "pub-${name}-${details.version}"; url = details.description.url; rev = details.description.resolved-ref; hash = gitHashes.${name} or (throw "A Git hash is required for ${name}! Set to an empty string to obtain it."); }).overrideAttrs ({ passthru ? { }, ... }: { passthru = passthru // { packageRoot = details.description.path; }; }); mkPathDependencySource = name: details: assert lib.assertMsg details.description.relative "Only relative paths are supported - ${name} has an absolue path!"; (if lib.isDerivation src then src else (runCommand "pub-${name}-${details.version}" { } ''cp -r '${src}' "$out"'')).overrideAttrs ({ passthru ? { }, ... }: { passthru = passthru // { packageRoot = "${packageRoot}/${details.description.path}"; }; }); mkSdkDependencySource = name: details: (sdkSourceBuilders.${details.description} or (throw "No SDK source builder has been given for ${details.description}!")) name; addDependencySourceUtils = dependencySource: details: dependencySource.overrideAttrs ({ passthru, ... }: { passthru = passthru // { inherit (details) version; }; }); sourceBuilders = callPackage ../../../development/compilers/dart/package-source-builders { } // customSourceBuilders; dependencySources = lib.filterAttrs (name: src: src != null) (builtins.mapAttrs (name: details: (sourceBuilders.${name} or ({ src, ... }: src)) { inherit (details) version source; src = ((addDependencySourceUtils (({ "hosted" = mkHostedDependencySource; "git" = mkGitDependencySource; "path" = mkPathDependencySource; "sdk" = mkSdkDependencySource; }.${details.source} name) details)) details); }) pubspecLock.packages); in { inherit # An attribute set of dependency categories to package name lists. dependencies # An attribute set of package names to their versions. dependencyVersions # An attribute set of package names to their sources. dependencySources; }