summary refs log tree commit diff
path: root/pkgs/build-support/flutter/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/build-support/flutter/default.nix')
-rw-r--r--pkgs/build-support/flutter/default.nix277
1 files changed, 277 insertions, 0 deletions
diff --git a/pkgs/build-support/flutter/default.nix b/pkgs/build-support/flutter/default.nix
new file mode 100644
index 00000000000..5208dbc7d05
--- /dev/null
+++ b/pkgs/build-support/flutter/default.nix
@@ -0,0 +1,277 @@
+{ flutter
+, lib
+, llvmPackages_13
+, cmake
+, ninja
+, pkg-config
+, wrapGAppsHook
+, autoPatchelfHook
+, util-linux
+, libselinux
+, libsepol
+, libthai
+, libdatrie
+, libxkbcommon
+, at-spi2-core
+, libsecret
+, jsoncpp
+, xorg
+, dbus
+, gtk3
+, glib
+, pcre
+, libepoxy
+, stdenvNoCC
+, cacert
+, git
+, dart
+, nukeReferences
+, targetPlatform
+, bash
+, curl
+, unzip
+, which
+, xz
+}:
+
+# absolutely no mac support for now
+
+args:
+let
+  pl = n: "##FLUTTER_${n}_PLACEHOLDER_MARKER##";
+  placeholder_deps = pl "DEPS";
+  placeholder_flutter = pl "FLUTTER";
+  fetchAttrs = [ "src" "sourceRoot" "setSourceRoot" "unpackPhase" "patches" ];
+  getAttrsOrNull = names: attrs: lib.genAttrs names (name: if attrs ? ${name} then attrs.${name} else null);
+  flutterDeps = [
+    # flutter deps
+    flutter.unwrapped
+    bash
+    curl
+    flutter.dart
+    git
+    unzip
+    which
+    xz
+  ];
+  self =
+(self: llvmPackages_13.stdenv.mkDerivation (args // {
+  deps = stdenvNoCC.mkDerivation (lib.recursiveUpdate (getAttrsOrNull fetchAttrs args) {
+    name = "${self.name}-deps-flutter-v${flutter.unwrapped.version}-${targetPlatform.system}.tar.gz";
+
+    nativeBuildInputs = flutterDeps ++ [
+      nukeReferences
+    ];
+
+    installPhase = ''
+      . ${../fetchgit/deterministic-git}
+
+      TMP=$(mktemp -d)
+
+      export HOME="$TMP"
+      export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
+      export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1
+
+      flutter config --no-analytics &>/dev/null # mute first-run
+      flutter config --enable-linux-desktop
+      flutter packages get
+      flutter build linux || true # so it downloads tools
+
+      RES="$TMP"
+
+      mkdir -p "$RES/f"
+
+      # so we can use lock, diff yaml
+      cp "pubspec.yaml" "$RES"
+      cp "pubspec.lock" "$RES"
+      mv .dart_tool .flutter-plugins .flutter-plugins-dependencies .packages "$RES/f"
+
+      # replace paths with placeholders
+      find "$RES" -type f -exec sed -i \
+        -e s,$TMP,${placeholder_deps},g \
+        -e s,${flutter.unwrapped},${placeholder_flutter},g \
+        {} +
+
+      remove_line_matching() {
+        replace_line_matching "$1" "$2" ""
+      }
+
+      replace_line_matching() {
+        sed "s|.*$2.*|$3|g" -r -i "$1"
+      }
+
+      # nuke nondeterminism
+
+      # clientId is random
+      remove_line_matching "$RES/.flutter" clientId
+
+      # deterministic git repos
+      find "$RES" -iname .git -type d | while read -r repoGit; do
+        make_deterministic_repo "$(dirname "$repoGit")"
+      done
+
+      # dart _fetchedAt, etc
+      DART_DATE=$(date --date="@$SOURCE_DATE_EPOCH" -In | sed "s|,|.|g" | sed "s|+.*||g")
+      find "$RES/.pub-cache" -iname "*.json" -exec sed -r 's|.*_fetchedAt.*|    "_fetchedAt": "'"$DART_DATE"'",|g' -i {} +
+      replace_line_matching "$RES/f/.dart_tool/package_config.json" '"generated"' '"generated": "'"$DART_DATE"'",'
+      replace_line_matching "$RES/f/.flutter-plugins-dependencies" '"date_created"' '"date_created": "'"$DART_DATE"'",'
+      remove_line_matching "$RES/f/.packages" "Generated by pub"
+
+      # nuke refs
+      find "$RES" -type f -exec nuke-refs {} +
+
+      # Build a reproducible tar, per instructions at https://reproducible-builds.org/docs/archives/
+      tar --owner=0 --group=0 --numeric-owner --format=gnu \
+          --sort=name --mtime="@$SOURCE_DATE_EPOCH" \
+          -czf "$out" -C "$RES" .
+    '';
+
+    GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";
+
+    impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
+      "GIT_PROXY_COMMAND" "NIX_GIT_SSL_CAINFO" "SOCKS_SERVER"
+    ];
+
+    # unnecesarry
+    dontFixup = true;
+
+    outputHashAlgo = if self ? vendorHash then null else "sha256";
+    # outputHashMode = "recursive";
+    outputHash = if self ? vendorHash then
+      self.vendorHash
+    else if self ? vendorSha256 then
+      self.vendorSha256
+    else
+      lib.fakeSha256;
+
+  });
+
+  nativeBuildInputs = flutterDeps ++ [
+    # flutter dev tools
+    cmake
+    ninja
+    pkg-config
+    wrapGAppsHook
+    # flutter likes dynamic linking
+    autoPatchelfHook
+  ] ++ lib.optionals (args ? nativeBuildInputs) args.nativeBuildInputs;
+
+  buildInputs = [
+    # cmake deps
+    gtk3
+    glib
+    pcre
+    util-linux
+    # also required by cmake, not sure if really needed or dep of all packages
+    libselinux
+    libsepol
+    libthai
+    libdatrie
+    xorg.libXdmcp
+    xorg.libXtst
+    libxkbcommon
+    dbus
+    at-spi2-core
+    libsecret
+    jsoncpp
+    # build deps
+    xorg.libX11
+    # directly required by build
+    libepoxy
+  ] ++ lib.optionals (args ? buildInputs) args.buildInputs;
+
+  # TODO: do we need this?
+  NIX_LDFLAGS = "-rpath ${lib.makeLibraryPath self.buildInputs}";
+  NIX_CFLAGS_COMPILE = "-I${xorg.libX11}/include";
+  LD_LIBRARY_PATH = lib.makeLibraryPath self.buildInputs;
+
+  configurePhase = ''
+    runHook preConfigure
+
+    # for some reason fluffychat build breaks without this - seems file gets overriden by some tool
+    cp pubspec.yaml pubspec-backup
+
+    # we get this from $depsFolder so disabled for now, but we might need it again once deps are fetched properly
+    # flutter config --no-analytics >/dev/null 2>/dev/null # mute first-run
+    # flutter config --enable-linux-desktop
+
+    # extract deps
+    depsFolder=$(mktemp -d)
+    tar xzf "$deps" -C "$depsFolder"
+
+    # after extracting update paths to point to real paths
+    find "$depsFolder" -type f -exec sed -i \
+      -e s,${placeholder_deps},$depsFolder,g \
+      -e s,${placeholder_flutter},${flutter.unwrapped},g \
+      {} +
+
+    # ensure we're using a lockfile for the right package version
+    if [ -e pubspec.lock ]; then
+      # diff -u pubspec.lock $depsFolder/pubspec.lock
+      true
+    else
+      cp -v "$depsFolder/pubspec.lock" .
+    fi
+    diff -u pubspec.yaml $depsFolder/pubspec.yaml
+
+    mv -v $(find $depsFolder/f -type f) .
+
+    # prepare
+    export HOME=$depsFolder
+    export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
+    export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1
+
+    # binaries need to be patched
+    autoPatchelf -- "$depsFolder"
+
+    runHook postConfigure
+  '';
+
+  buildPhase = ''
+    runHook preBuild
+
+    # for some reason fluffychat build breaks without this - seems file gets overriden by some tool
+    mv pubspec-backup pubspec.yaml
+    mkdir -p build/flutter_assets/fonts
+
+    flutter packages get --offline -v
+    flutter build linux --release -v
+
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+
+    built=build/linux/*/release/bundle
+
+    mkdir -p $out/bin
+    mv $built $out/app
+
+    for f in $built/data/flutter_assets/assets/*.desktop; do
+      install -D $f $out/share/applications/$(basename $f)
+    done
+    for f in $(find $out/app -maxdepth 1 -type f); do
+      ln -s $f $out/bin/$(basename $f)
+    done
+
+    # this confuses autopatchelf hook otherwise
+    rm -rf "$depsFolder"
+
+    # make *.so executable
+    find $out/app -iname "*.so" -type f -exec chmod +x {} +
+
+    # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral
+    for f in $(find $out/app -executable -type f); do
+      if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also
+        echo "strip RPath of $f"
+        newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g")
+        patchelf --set-rpath "$newrp" "$f"
+      fi
+    done
+
+    runHook postInstall
+  '';
+})) self;
+in
+  self