Unverified Commit d4652d33 authored by Kira Bruneau's avatar Kira Bruneau Committed by GitHub
Browse files

Merge pull request #229770 from Misterio77/init-buildDartPackage

buildDartApplication: init
parents 8317bbe5 70d3f5c0
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
# Dart {#sec-language-dart}

## Dart applications {#ssec-dart-applications}

The function `buildDartApplication` builds Dart applications managed with pub.

It fetches its Dart dependencies automatically through `fetchDartDeps`, and (through a series of hooks) builds and installs the executables specified in the pubspec file. The hooks can be used in other derivations, if needed. The phases can also be overridden to do something different from installing binaries.

If you are packaging a Flutter desktop application, use [`buildFlutterApplication`](#ssec-dart-flutter) instead.

`vendorHash`: is the hash of the output of the dependency fetcher derivation. To obtain it, simply set it to `lib.fakeHash` (or omit it) and run the build ([more details here](#sec-source-hashes)).

If the upstream source is missing a `pubspec.lock` file, you'll have to vendor one and specify it using `pubspecLockFile`. If it is needed, one will be generated for you and printed when attempting to build the derivation.

The `dart` commands run can be overridden through `pubGetScript` and `dartCompileCommand`, you can also add flags using `dartCompileFlags` or `dartJitFlags`.

Dart supports multiple [outputs types](https://dart.dev/tools/dart-compile#types-of-output), you can choose between them using `dartOutputType` (defaults to `exe`). If you want to override the binaries path or the source path they come from, you can use `dartEntryPoints`. Outputs that require a runtime will automatically be wrapped with the relevant runtime (`dartaotruntime` for `aot-snapshot`, `dart run` for `jit-snapshot` and `kernel`, `node` for `js`), this can be overridden through `dartRuntimeCommand`.

```nix
{ buildDartApplication, fetchFromGitHub }:

buildDartApplication rec {
  pname = "dart-sass";
  version = "1.62.1";

  src = fetchFromGitHub {
    owner = "sass";
    repo = pname;
    rev = version;
    hash = "sha256-U6enz8yJcc4Wf8m54eYIAnVg/jsGi247Wy8lp1r1wg4=";
  };

  pubspecLockFile = ./pubspec.lock;
  vendorHash = "sha256-Atm7zfnDambN/BmmUf4BG0yUz/y6xWzf0reDw3Ad41s=";
}
```

## Flutter applications {#ssec-dart-flutter}

The function `buildFlutterApplication` builds Flutter applications.

The deps.json file must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` when outside of Nixpkgs, as it relies on import-from-derivation.

A `pubspec.lock` file must be available. See the [Dart documentation](#ssec-dart-applications) for more details.

```nix
{  flutter, fetchFromGitHub }:

flutter.buildFlutterApplication {
  pname = "firmware-updater";
  version = "unstable-2023-04-30";

  src = fetchFromGitHub {
    owner = "canonical";
    repo = "firmware-updater";
    rev = "6e7dbdb64e344633ea62874b54ff3990bd3b8440";
    sha256 = "sha256-s5mwtr5MSPqLMN+k851+pFIFFPa0N1hqz97ys050tFA=";
    fetchSubmodules = true;
  };

  pubspecLockFile = ./pubspec.lock;
  depsListFile = ./deps.json;
  vendorHash = "sha256-cdMO+tr6kYiN5xKXa+uTMAcFf2C75F3wVPrn21G4QPQ=";
}
```
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 <xi:include href="crystal.section.xml" />
 <xi:include href="cuda.section.xml" />
 <xi:include href="cuelang.section.xml" />
 <xi:include href="dart.section.xml" />
 <xi:include href="dhall.section.xml" />
 <xi:include href="dotnet.section.xml" />
 <xi:include href="emscripten.section.xml" />
+66 −0
Original line number Diff line number Diff line
{ lib, stdenv, fetchDartDeps, writeText, dartHooks, makeWrapper, dart, nodejs }:

{ pubGetScript ? "dart pub get"

  # 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

, pubspecLockFile ? null
, vendorHash ? ""
, ...
}@args:

let
  dartDeps = fetchDartDeps {
    buildDrvArgs = args;
    inherit pubGetScript vendorHash pubspecLockFile;
  };
  inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook;
in
assert !(builtins.isString dartOutputType && dartOutputType != "") ->
  throw "dartOutputType must be a non-empty string";
stdenv.mkDerivation (args // {
  inherit pubGetScript dartCompileCommand dartOutputType dartRuntimeCommand
    dartCompileFlags dartJitFlags;

    dartEntryPoints =
      if (dartEntryPoints != null)
      then writeText "entrypoints.json" (builtins.toJSON dartEntryPoints)
      else null;

  nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
    dart
    dartDeps
    dartConfigHook
    dartBuildHook
    dartInstallHook
    makeWrapper
  ];

  # 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");

  passthru = { inherit dartDeps; } // (args.passthru or { });

  meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; };
})
+34 −0
Original line number Diff line number Diff line
# 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
+12 −0
Original line number Diff line number Diff line
# shellcheck shell=bash

dartConfigHook() {
    echo "Executing dartConfigHook"

    echo "Installing dependencies"
    eval "$pubGetScript" --offline

    echo "Finished dartConfigHook"
}

postConfigureHooks+=(dartConfigHook)
Loading