about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support/dart/build-dart-application
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/build-support/dart/build-dart-application')
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix132
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/generators.nix74
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-build-hook.sh34
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh70
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh35
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh43
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/default.nix20
7 files changed, 408 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix b/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix
new file mode 100644
index 000000000000..c99b8bbf325e
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix
@@ -0,0 +1,132 @@
+{ lib
+, stdenv
+, callPackage
+, runCommand
+, writeText
+, pub2nix
+, dartHooks
+, makeWrapper
+, dart
+, nodejs
+, darwin
+, jq
+, yq
+}:
+
+{ src
+, sourceRoot ? "source"
+, packageRoot ? (lib.removePrefix "/" (lib.removePrefix "source" sourceRoot))
+, gitHashes ? { }
+, sdkSourceBuilders ? { }
+, customSourceBuilders ? { }
+
+, sdkSetupScript ? ""
+, extraPackageConfigSetup ? ""
+
+  # Output type to produce. Can be any kind supported by dart
+  # https://dart.dev/tools/dart-compile#types-of-output
+  # If using jit, you might want to pass some arguments to `dartJitFlags`
+, dartOutputType ? "exe"
+, dartCompileCommand ? "dart compile"
+, dartCompileFlags ? [ ]
+  # These come at the end of the command, useful to pass flags to the jit run
+, dartJitFlags ? [ ]
+
+  # Attrset of entry point files to build and install.
+  # Where key is the final binary path and value is the source file path
+  # e.g. { "bin/foo" = "bin/main.dart";  }
+  # Set to null to read executables from pubspec.yaml
+, dartEntryPoints ? null
+  # Used when wrapping aot, jit, kernel, and js builds.
+  # Set to null to disable wrapping.
+, dartRuntimeCommand ? if dartOutputType == "aot-snapshot" then "${dart}/bin/dartaotruntime"
+  else if (dartOutputType == "jit-snapshot" || dartOutputType == "kernel") then "${dart}/bin/dart"
+  else if dartOutputType == "js" then "${nodejs}/bin/node"
+  else null
+
+, runtimeDependencies ? [ ]
+, extraWrapProgramArgs ? ""
+
+, autoPubspecLock ? null
+, pubspecLock ? if autoPubspecLock == null then
+    throw "The pubspecLock argument is required. If import-from-derivation is allowed (it isn't in Nixpkgs), you can set autoPubspecLock to the path to a pubspec.lock instead."
+  else
+    assert lib.assertMsg (builtins.pathExists autoPubspecLock) "The pubspec.lock file could not be found!";
+    lib.importJSON (runCommand "${lib.getName args}-pubspec-lock-json" { nativeBuildInputs = [ yq ]; } ''yq . '${autoPubspecLock}' > "$out"'')
+, ...
+}@args:
+
+let
+  generators = callPackage ./generators.nix { inherit dart; } { buildDrvArgs = args; };
+
+  pubspecLockFile = builtins.toJSON pubspecLock;
+  pubspecLockData = pub2nix.readPubspecLock { inherit src packageRoot pubspecLock gitHashes sdkSourceBuilders customSourceBuilders; };
+  packageConfig = generators.linkPackageConfig {
+    packageConfig = pub2nix.generatePackageConfig {
+      pname = if args.pname != null then "${args.pname}-${args.version}" else null;
+
+      dependencies =
+        # Ideally, we'd only include the main dependencies and their transitive
+        # dependencies.
+        #
+        # The pubspec.lock file does not contain information about where
+        # transitive dependencies come from, though, and it would be weird to
+        # include the transitive dependencies of dev and override dependencies
+        # without including the dev and override dependencies themselves.
+        builtins.concatLists (builtins.attrValues pubspecLockData.dependencies);
+
+      inherit (pubspecLockData) dependencySources;
+    };
+    extraSetupCommands = extraPackageConfigSetup;
+  };
+
+  inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook dartFixupHook;
+
+  baseDerivation = stdenv.mkDerivation (finalAttrs: (builtins.removeAttrs args [ "gitHashes" "sdkSourceBuilders" "pubspecLock" "customSourceBuilders" ]) // {
+    inherit pubspecLockFile packageConfig sdkSetupScript
+      dartCompileCommand dartOutputType dartRuntimeCommand dartCompileFlags
+      dartJitFlags;
+
+    outputs = [ "out" "pubcache" ] ++ args.outputs or [ ];
+
+    dartEntryPoints =
+      if (dartEntryPoints != null)
+      then writeText "entrypoints.json" (builtins.toJSON dartEntryPoints)
+      else null;
+
+    runtimeDependencies = map lib.getLib runtimeDependencies;
+
+    nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
+      dart
+      dartConfigHook
+      dartBuildHook
+      dartInstallHook
+      dartFixupHook
+      makeWrapper
+      jq
+    ] ++ lib.optionals stdenv.isDarwin [
+      darwin.sigtool
+    ] ++
+      # Ensure that we inherit the propagated build inputs from the dependencies.
+      builtins.attrValues pubspecLockData.dependencySources;
+
+    preConfigure = args.preConfigure or "" + ''
+      ln -sf "$pubspecLockFilePath" pubspec.lock
+    '';
+
+    # When stripping, it seems some ELF information is lost and the dart VM cli
+    # runs instead of the expected program. Don't strip if it's an exe output.
+    dontStrip = args.dontStrip or (dartOutputType == "exe");
+
+    passAsFile = [ "pubspecLockFile" ];
+
+    passthru = {
+      pubspecLock = pubspecLockData;
+    } // (args.passthru or { });
+
+    meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; };
+  });
+in
+assert !(builtins.isString dartOutputType && dartOutputType != "") ->
+throw "dartOutputType must be a non-empty string";
+baseDerivation
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/generators.nix b/nixpkgs/pkgs/build-support/dart/build-dart-application/generators.nix
new file mode 100644
index 000000000000..f01a09305dba
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/generators.nix
@@ -0,0 +1,74 @@
+{ lib
+, stdenvNoCC
+, dart
+, dartHooks
+, jq
+, yq
+, cacert
+}:
+
+{
+  # Arguments used in the derivation that builds the Dart package.
+  # Passing these is recommended to ensure that the same steps are made to
+  # prepare the sources in both this derivation and the one that builds the Dart
+  # package.
+  buildDrvArgs ? { }
+, ...
+}@args:
+
+# This is a derivation and setup hook that can be used to fetch dependencies for Dart projects.
+# It is designed to be placed in the nativeBuildInputs of a derivation that builds a Dart package.
+# Providing the buildDrvArgs argument is highly recommended.
+let
+  buildDrvInheritArgNames = [
+    "name"
+    "pname"
+    "version"
+    "src"
+    "sourceRoot"
+    "setSourceRoot"
+    "preUnpack"
+    "unpackPhase"
+    "unpackCmd"
+    "postUnpack"
+    "prePatch"
+    "patchPhase"
+    "patches"
+    "patchFlags"
+    "postPatch"
+  ];
+
+  buildDrvInheritArgs = builtins.foldl'
+    (attrs: arg:
+      if buildDrvArgs ? ${arg}
+      then attrs // { ${arg} = buildDrvArgs.${arg}; }
+      else attrs)
+    { }
+    buildDrvInheritArgNames;
+
+  drvArgs = buildDrvInheritArgs // (removeAttrs args [ "buildDrvArgs" ]);
+  name = (if drvArgs ? name then drvArgs.name else "${drvArgs.pname}-${drvArgs.version}");
+
+  # Adds the root package to a dependency package_config.json file from pub2nix.
+  linkPackageConfig = { packageConfig, extraSetupCommands ? "" }: stdenvNoCC.mkDerivation (drvArgs // {
+    name = "${name}-package-config-with-root.json";
+
+    nativeBuildInputs = drvArgs.nativeBuildInputs or [ ] ++ args.nativeBuildInputs or [ ] ++ [ jq yq ];
+
+    dontBuild = true;
+
+    installPhase = ''
+      runHook preInstall
+
+      packageName="$(yq --raw-output .name pubspec.yaml)"
+      jq --arg name "$packageName" '.packages |= . + [{ name: $name, rootUri: "../", packageUri: "lib/" }]' '${packageConfig}' > "$out"
+      ${extraSetupCommands}
+
+      runHook postInstall
+    '';
+  });
+in
+{
+  inherit
+    linkPackageConfig;
+}
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-build-hook.sh b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-build-hook.sh
new file mode 100644
index 000000000000..23ebfbd6e66e
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-build-hook.sh
@@ -0,0 +1,34 @@
+# shellcheck shell=bash
+
+# Outputs line-separated "${dest}\t${source}"
+_getDartEntryPoints() {
+    if [ -n "$dartEntryPoints" ]; then
+        @jq@ -r '(to_entries | map(.key + "\t" + .value) | join("\n"))' "$dartEntryPoints"
+    else
+        # The pubspec executables section follows the pattern:
+        # <output-bin-name>: [source-file-name]
+        # Where source-file-name defaults to output-bin-name if omited
+        @yq@ -r '(.executables | to_entries | map("bin/" + .key + "\t" + "bin/" + (.value // .key) + ".dart") | join("\n"))' pubspec.yaml
+    fi
+}
+
+dartBuildHook() {
+    echo "Executing dartBuildHook"
+
+    runHook preBuild
+
+    while IFS=$'\t' read -ra target; do
+        dest="${target[0]}"
+        src="${target[1]}"
+        eval "$dartCompileCommand" "$dartOutputType" \
+            -o "$dest" "${dartCompileFlags[@]}" "$src" "${dartJitFlags[@]}"
+    done < <(_getDartEntryPoints)
+
+    runHook postBuild
+
+    echo "Finished dartBuildHook"
+}
+
+if [ -z "${dontDartBuild-}" ] && [ -z "${buildPhase-}" ]; then
+    buildPhase=dartBuildHook
+fi
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh
new file mode 100644
index 000000000000..50754a7b56d4
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh
@@ -0,0 +1,70 @@
+# shellcheck shell=bash
+
+dartConfigHook() {
+    echo "Executing dartConfigHook"
+
+    echo "Setting up SDK"
+    eval "$sdkSetupScript"
+
+    echo "Installing dependencies"
+    mkdir -p .dart_tool
+    cp "$packageConfig" .dart_tool/package_config.json
+
+    packagePath() {
+        jq --raw-output --arg name "$1" '.packages.[] | select(.name == $name) .rootUri | sub("file://"; "")' .dart_tool/package_config.json
+    }
+
+    # Runs a Dart executable from a package with a custom path.
+    #
+    # Usage:
+    # packageRunCustom <package> [executable] [bin_dir]
+    #
+    # By default, [bin_dir] is "bin", and [executable] is <package>.
+    # i.e. `packageRunCustom build_runner` is equivalent to `packageRunCustom build_runner build_runner bin`, which runs `bin/build_runner.dart` from the build_runner package.
+    packageRunCustom() {
+        local args=()
+        local passthrough=()
+
+        while [ $# -gt 0 ]; do
+            if [ "$1" != "--" ]; then
+                args+=("$1")
+                shift
+            else
+                shift
+                passthrough=("$@")
+                break
+            fi
+        done
+
+        local name="${args[0]}"
+        local path="${args[1]:-$name}"
+        local prefix="${args[2]:-bin}"
+
+        dart --packages=.dart_tool/package_config.json "$(packagePath "$name")/$prefix/$path.dart" "${passthrough[@]}"
+    }
+
+    # Runs a Dart executable from a package.
+    #
+    # Usage:
+    # packageRun <package> [-e executable] [...]
+    #
+    # To run an executable from an unconventional location, use packageRunCustom.
+    packageRun() {
+        local name="$1"
+        shift
+
+        local executableName="$name"
+        if [ "$1" = "-e" ]; then
+          shift
+          executableName="$1"
+          shift
+        fi
+
+        fileName="$(@yq@ --raw-output --arg name "$executableName" '.executables.[$name] // $name' "$(packagePath "$name")/pubspec.yaml")"
+        packageRunCustom "$name" "$fileName" -- "$@"
+    }
+
+    echo "Finished dartConfigHook"
+}
+
+postConfigureHooks+=(dartConfigHook)
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh
new file mode 100644
index 000000000000..60bd74871c92
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh
@@ -0,0 +1,35 @@
+# shellcheck shell=bash
+
+dartFixupHook() {
+    echo "Executing dartFixupHook"
+
+    declare -a wrapProgramArgs
+
+    # Add runtime library dependencies to the LD_LIBRARY_PATH.
+    # For some reason, the RUNPATH of the executable is not used to load dynamic libraries in dart:ffi with DynamicLibrary.open().
+    #
+    # This could alternatively be fixed with patchelf --add-needed, but this would cause all the libraries to be opened immediately,
+    # which is not what application authors expect.
+    APPLICATION_LD_LIBRARY_PATH=""
+    for runtimeDependency in "${runtimeDependencies[@]}"; do
+      addToSearchPath APPLICATION_LD_LIBRARY_PATH "${runtimeDependency}/lib"
+    done
+    if [[ ! -z "$APPLICATION_LD_LIBRARY_PATH" ]]; then
+        wrapProgramArgs+=(--suffix LD_LIBRARY_PATH : \"$APPLICATION_LD_LIBRARY_PATH\")
+    fi
+
+    if [[ ! -z "$extraWrapProgramArgs" ]]; then
+        wrapProgramArgs+=("$extraWrapProgramArgs")
+    fi
+
+    if [ ${#wrapProgramArgs[@]} -ne 0 ]; then
+        for f in "$out"/bin/*; do
+            echo "Wrapping $f..."
+            eval "wrapProgram \"$f\" ${wrapProgramArgs[@]}"
+        done
+    fi
+
+    echo "Finished dartFixupHook"
+}
+
+postFixupHooks+=(dartFixupHook)
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh
new file mode 100644
index 000000000000..349a0dfdef0e
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh
@@ -0,0 +1,43 @@
+# shellcheck shell=bash
+
+dartInstallHook() {
+    echo "Executing dartInstallHook"
+
+    runHook preInstall
+
+    # Install snapshots and executables.
+    mkdir -p "$out"
+    while IFS=$'\t' read -ra target; do
+        dest="${target[0]}"
+        # Wrap with runtime command, if it's defined
+        if [ -n "$dartRuntimeCommand" ]; then
+            install -D "$dest" "$out/share/$dest"
+            makeWrapper "$dartRuntimeCommand" "$out/$dest" \
+                --add-flags "$out/share/$dest"
+        else
+            install -Dm755 "$dest" "$out/$dest"
+        fi
+    done < <(_getDartEntryPoints)
+
+    runHook postInstall
+
+    echo "Finished dartInstallHook"
+}
+
+dartInstallCacheHook() {
+    echo "Executing dartInstallCacheHook"
+
+    # Install the package_config.json file.
+    mkdir -p "$pubcache"
+    cp .dart_tool/package_config.json "$pubcache/package_config.json"
+
+    echo "Finished dartInstallCacheHook"
+}
+
+if [ -z "${dontDartInstall-}" ] && [ -z "${installPhase-}" ]; then
+    installPhase=dartInstallHook
+fi
+
+if [ -z "${dontDartInstallCache-}" ]; then
+    postInstallHooks+=(dartInstallCacheHook)
+fi
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/default.nix b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/default.nix
new file mode 100644
index 000000000000..253d3132ad02
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/default.nix
@@ -0,0 +1,20 @@
+{ lib, makeSetupHook, dart, yq, jq }:
+
+{
+  dartConfigHook = makeSetupHook {
+    name = "dart-config-hook";
+    substitutions.yq = "${yq}/bin/yq";
+    substitutions.jq = "${jq}/bin/jq";
+  } ./dart-config-hook.sh;
+  dartBuildHook = makeSetupHook {
+    name = "dart-build-hook";
+    substitutions.yq = "${yq}/bin/yq";
+    substitutions.jq = "${jq}/bin/jq";
+  } ./dart-build-hook.sh;
+  dartInstallHook = makeSetupHook {
+    name = "dart-install-hook";
+  } ./dart-install-hook.sh;
+  dartFixupHook = makeSetupHook {
+    name = "dart-fixup-hook";
+  } ./dart-fixup-hook.sh;
+}