push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
# Schema:
# ${flutterVersion}.${targetPlatform}.${hostPlatform}
#
# aarch64-darwin as a host is not yet supported.
# https://github.com/flutter/flutter/issues/60118
{
lib,
runCommand,
xorg,
cacert,
unzip,
flutterPlatform,
systemPlatform,
flutter,
hash,
}:
let
flutterPlatforms = [
"android"
"ios"
"web"
"linux"
"windows"
"macos"
"fuchsia"
"universal"
];
flutter' = flutter.override {
# Use a version of Flutter with just enough capabilities to download
# artifacts.
supportedTargetFlutterPlatforms = [ ];
# Modify flutter-tool's system platform in order to get the desired platform's hashes.
flutter = flutter.unwrapped.override {
flutterTools = flutter.unwrapped.tools.override {
inherit systemPlatform;
};
};
};
in
runCommand "flutter-artifacts-${flutterPlatform}-${systemPlatform}"
{
nativeBuildInputs = [
xorg.lndir
flutter'
unzip
];
NIX_FLUTTER_TOOLS_VM_OPTIONS = "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt";
NIX_FLUTTER_OPERATING_SYSTEM =
{
"x86_64-linux" = "linux";
"aarch64-linux" = "linux";
"x86_64-darwin" = "macos";
"aarch64-darwin" = "macos";
}
.${systemPlatform};
outputHash = hash;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
passthru = {
inherit flutterPlatform;
};
}
(
''
export FLUTTER_ROOT="$NIX_BUILD_TOP"
lndir -silent '${flutter'}' "$FLUTTER_ROOT"
rm -rf "$FLUTTER_ROOT/bin/cache"
mkdir "$FLUTTER_ROOT/bin/cache"
''
+ lib.optionalString (lib.versionAtLeast flutter'.version "3.26") ''
mkdir "$FLUTTER_ROOT/bin/cache/dart-sdk"
lndir -silent '${flutter'}/bin/cache/dart-sdk' "$FLUTTER_ROOT/bin/cache/dart-sdk"
''
# Could not determine engine revision
+ lib.optionalString (lib.versionAtLeast flutter'.version "3.32") ''
cp '${flutter'}/bin/internal/engine.version' "$FLUTTER_ROOT/bin/cache/engine.stamp"
''
+ ''
HOME="$(mktemp -d)" flutter precache ${
lib.optionalString (
flutter ? engine && flutter.engine.meta.available
) "--local-engine ${flutter.engine.outName}"
} \
-v '--${flutterPlatform}' ${
builtins.concatStringsSep " " (map (p: "'--no-${p}'") (lib.remove flutterPlatform flutterPlatforms))
}
rm -rf "$FLUTTER_ROOT/bin/cache/lockfile"
''
+ lib.optionalString (lib.versionAtLeast flutter'.version "3.26") ''
rm -rf "$FLUTTER_ROOT/bin/cache/dart-sdk"
''
+ ''
find "$FLUTTER_ROOT" -type l -lname '${flutter'}/*' -delete
cp -r bin/cache "$out"
''
)

View File

@@ -0,0 +1,14 @@
{ }:
{
buildInputs ? [ ],
...
}:
{
postPatch = ''
if [ "$pname" == "flutter-tools" ]; then
# Use arm64 instead of arm64e.
substituteInPlace lib/src/ios/xcodeproj.dart \
--replace-fail arm64e arm64
fi
'';
}

View File

@@ -0,0 +1,12 @@
{
gtk3,
}:
{
buildInputs ? [ ],
...
}:
{
buildInputs = buildInputs ++ [ gtk3 ];
}

View File

@@ -0,0 +1,30 @@
{
lib,
stdenv,
callPackage,
autoPatchelfHook,
src,
}:
(stdenv.mkDerivation {
inherit (src) name;
inherit src;
nativeBuildInputs = lib.optional stdenv.hostPlatform.isLinux autoPatchelfHook;
installPhase = ''
runHook preInstall
mkdir -p "$out/bin"
cp -r . "$out/bin/cache"
rm -f "$out/bin/cache/flutter.version.json"
runHook postInstall
'';
}).overrideAttrs
(
if builtins.pathExists (./overrides + "/${src.flutterPlatform}.nix") then
callPackage (./overrides + "/${src.flutterPlatform}.nix") { }
else
({ ... }: { })
)

View File

@@ -0,0 +1,245 @@
{
lib,
callPackage,
runCommand,
makeWrapper,
wrapGAppsHook3,
buildDartApplication,
cacert,
glib,
flutter,
pkg-config,
buildPackages,
}:
# absolutely no mac support for now
{
pubGetScript ? null,
flutterBuildFlags ? [ ],
targetFlutterPlatform ? "linux",
extraWrapProgramArgs ? "",
flutterMode ? null,
...
}@args:
let
hasEngine = flutter ? engine && flutter.engine != null && flutter.engine.meta.available;
flutterMode = args.flutterMode or (if hasEngine then flutter.engine.runtimeMode else "release");
flutterFlags = lib.optional hasEngine "--local-engine host_${flutterMode}${
lib.optionalString (!flutter.engine.isOptimized) "_unopt"
}";
flutterBuildFlags = [
"--${flutterMode}"
]
++ (args.flutterBuildFlags or [ ])
++ flutterFlags;
builderArgs =
let
universal = args // {
inherit flutterMode flutterFlags flutterBuildFlags;
sdkSetupScript = ''
# Pub needs SSL certificates. Dart normally looks in a hardcoded path.
# https://github.com/dart-lang/sdk/blob/3.1.0/runtime/bin/security_context_linux.cc#L48
#
# Dart does not respect SSL_CERT_FILE...
# https://github.com/dart-lang/sdk/issues/48506
# ...and Flutter does not support --root-certs-file, so the path cannot be manually set.
# https://github.com/flutter/flutter/issues/56607
# https://github.com/flutter/flutter/issues/113594
#
# libredirect is of no use either, as Flutter does not pass any
# environment variables (including LD_PRELOAD) to the Pub process.
#
# Instead, Flutter is patched to allow the path to the Dart binary used for
# Pub commands to be overriden.
export NIX_FLUTTER_PUB_DART="${
runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } ''
mkdir -p "$out/bin"
makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \
--add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt"
''
}/bin/dart"
export HOME="$NIX_BUILD_TOP"
flutter config $flutterFlags --no-analytics &>/dev/null # mute first-run
flutter config $flutterFlags --enable-linux-desktop >/dev/null
'';
pubGetScript =
args.pubGetScript
or "flutter${lib.optionalString hasEngine " --local-engine $flutterMode"} pub get";
sdkSourceBuilders = {
# https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81
"flutter" =
name:
runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } ''
for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do
if [ -d "$path" ]; then
ln -s "$path" "$out"
break
fi
done
if [ ! -e "$out" ]; then
echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!'
exit 1
fi
'';
# https://github.com/dart-lang/pub/blob/e1fbda73d1ac597474b82882ee0bf6ecea5df108/lib/src/sdk/dart.dart#L80
"dart" =
name:
runCommand "dart-sdk-${name}" { passthru.packageRoot = "."; } ''
for path in '${flutter.dart}/pkg/${name}'; do
if [ -d "$path" ]; then
ln -s "$path" "$out"
break
fi
done
if [ ! -e "$out" ]; then
echo 1>&2 'The Dart SDK does not contain the requested package: ${name}!'
exit 1
fi
'';
};
# https://github.com/flutter/flutter/blob/edada7c56edf4a183c1735310e123c7f923584f1/packages/flutter_tools/lib/src/dart/pub.dart#L804
extraPackageConfigSetup = lib.optionalString (lib.versionOlder flutter.version "3.34.0") ''
if [ "$("${lib.getExe buildPackages.yq}" '.flutter.generate // false' pubspec.yaml)" = "true" ]; then
if ! "${lib.getExe buildPackages.jq}" -e '.packages[] | select(.name == "flutter_gen")' "$out" >/dev/null 2>&1; then
export TEMP_PACKAGES=$(mktemp)
"${lib.getExe buildPackages.jq}" '.packages |= . + [{
name: "flutter_gen",
rootUri: "flutter_gen",
languageVersion: "2.12"
}]' "$out" > "$TEMP_PACKAGES"
cp "$TEMP_PACKAGES" "$out"
rm "$TEMP_PACKAGES"
unset TEMP_PACKAGES
fi
fi
'';
};
in
{
inherit universal;
linux = universal // {
outputs = universal.outputs or [ ] ++ [ "debug" ];
nativeBuildInputs = (universal.nativeBuildInputs or [ ]) ++ [
wrapGAppsHook3
# Flutter requires pkg-config for Linux desktop support, and many plugins
# attempt to use it.
#
# It is available to the `flutter` tool through its wrapper, but it must be
# added here as well so the setup hook adds plugin dependencies to the
# pkg-config search paths.
pkg-config
];
buildInputs = (universal.buildInputs or [ ]) ++ [ glib ];
dontDartBuild = true;
buildPhase =
universal.buildPhase or ''
runHook preBuild
mkdir -p build/flutter_assets/fonts
flutter build linux -v --split-debug-info="$debug" $flutterBuildFlags
runHook postBuild
'';
dontDartInstall = true;
installPhase =
universal.installPhase or ''
runHook preInstall
built=build/linux/*/$flutterMode/bundle
mkdir -p $out/bin
mkdir -p $out/app
mv $built $out/app/$pname
for f in $(find $out/app/$pname -iname "*.desktop" -type f); do
install -D $f $out/share/applications/$(basename $f)
done
for f in $(find $out/app/$pname -maxdepth 1 -type f); do
ln -s $f $out/bin/$(basename $f)
done
# make *.so executable
find $out/app/$pname -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/$pname -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
'';
dontWrapGApps = true;
extraWrapProgramArgs = ''
''${gappsWrapperArgs[@]} \
${extraWrapProgramArgs}
'';
};
web = universal // {
dontDartBuild = true;
buildPhase =
universal.buildPhase or ''
runHook preBuild
mkdir -p build/flutter_assets/fonts
flutter build web -v $flutterBuildFlags
runHook postBuild
'';
dontDartInstall = true;
installPhase =
universal.installPhase or ''
runHook preInstall
cp -r build/web "$out"
runHook postInstall
'';
};
}
.${targetFlutterPlatform} or (throw "Unsupported Flutter host platform: ${targetFlutterPlatform}");
minimalFlutter = flutter.override {
supportedTargetFlutterPlatforms = [
"universal"
targetFlutterPlatform
];
};
buildAppWith = flutter: buildDartApplication.override { dart = flutter; };
in
buildAppWith minimalFlutter (
builderArgs
// {
passthru = builderArgs.passthru or { } // {
multiShell = buildAppWith flutter builderArgs;
};
}
)

View File

@@ -0,0 +1,139 @@
{
useNixpkgsEngine ? false,
callPackage,
fetchzip,
fetchFromGitHub,
dart,
lib,
stdenv,
runCommand,
}:
let
mkCustomFlutter = args: callPackage ./flutter.nix args;
wrapFlutter = flutter: callPackage ./wrapper.nix { inherit flutter; };
getPatches =
dir:
let
files = builtins.attrNames (builtins.readDir dir);
in
if (builtins.pathExists dir) then map (f: dir + ("/" + f)) files else [ ];
mkFlutter =
{
version,
engineVersion,
engineSwiftShaderHash,
engineSwiftShaderRev,
engineHashes,
enginePatches,
dartVersion,
flutterHash,
dartHash,
patches,
pubspecLock,
artifactHashes,
channel,
}:
let
args = {
inherit
version
engineVersion
engineSwiftShaderRev
engineSwiftShaderHash
engineHashes
enginePatches
patches
pubspecLock
artifactHashes
useNixpkgsEngine
channel
;
dart = dart.override {
version = dartVersion;
sources = {
"${dartVersion}-x86_64-linux" = fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-linux-x64-release.zip";
sha256 = dartHash.x86_64-linux;
};
"${dartVersion}-aarch64-linux" = fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-linux-arm64-release.zip";
sha256 = dartHash.aarch64-linux;
};
"${dartVersion}-x86_64-darwin" = fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-macos-x64-release.zip";
sha256 = dartHash.x86_64-darwin;
};
"${dartVersion}-aarch64-darwin" = fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-macos-arm64-release.zip";
sha256 = dartHash.aarch64-darwin;
};
};
};
src =
let
source = fetchFromGitHub {
owner = "flutter";
repo = "flutter";
rev = version;
hash = flutterHash;
};
in
(
if lib.versionAtLeast version "3.32" then
# # Could not determine engine revision
(runCommand source.name { } ''
cp -r ${source} $out
chmod +w $out/bin
mkdir $out/bin/cache
cp $out/bin/internal/engine.version $out/bin/cache/engine.stamp
touch $out/bin/cache/engine.realm
'')
else
source
);
};
in
(mkCustomFlutter args).overrideAttrs (
prev: next: {
passthru = next.passthru // {
inherit wrapFlutter mkCustomFlutter mkFlutter;
buildFlutterApplication = callPackage ./build-support/build-flutter-application.nix {
flutter = wrapFlutter (mkCustomFlutter args);
};
};
}
);
flutterVersions = lib.mapAttrs' (
version: _:
let
versionDir = ./versions + "/${version}";
data = lib.importJSON (versionDir + "/data.json");
in
lib.nameValuePair "v${version}" (
wrapFlutter (
mkFlutter (
{
patches = (getPatches ./patches) ++ (getPatches (versionDir + "/patches"));
enginePatches = (getPatches ./engine/patches) ++ (getPatches (versionDir + "/engine/patches"));
}
// data
)
)
)
) (builtins.readDir ./versions);
stableFlutterVersions = lib.attrsets.filterAttrs (_: v: v.channel == "stable") flutterVersions;
betaFlutterVersions = lib.attrsets.filterAttrs (_: v: v.channel == "beta") flutterVersions;
in
flutterVersions
// {
inherit wrapFlutter mkFlutter;
}
// lib.optionalAttrs (betaFlutterVersions != { }) {
beta = flutterVersions.${lib.last (lib.naturalSort (builtins.attrNames betaFlutterVersions))};
}
// lib.optionalAttrs (stableFlutterVersions != { }) {
stable = flutterVersions.${lib.last (lib.naturalSort (builtins.attrNames stableFlutterVersions))};
}

View File

@@ -0,0 +1,48 @@
{ lib, platform }:
let
self = {
os =
if platform.isLinux then
"linux"
else if platform.isDarwin then
"macos"
else if platform.isWindows then
"windows"
else
throw "Unsupported OS \"${platform.parsed.kernel.name}\"";
alt-os = if platform.isDarwin then "mac" else self.os;
arch =
if platform.isx86_64 then
"amd64"
else if platform.isx86 && platform.is32bit then
"386"
else if platform.isAarch64 then
"arm64"
else if platform.isMips && platform.parsed.cpu.significantByte == "littleEndian" then
"mipsle"
else if platform.isMips64 then
"mips64${lib.optionalString (platform.parsed.cpu.significantByte == "littleEndian") "le"}"
else if platform.isPower64 then
"ppc64${lib.optionalString (platform.parsed.cpu.significantByte == "littleEndian") "le"}"
else if platform.isS390x then
"s390x"
else if platform.isRiscV64 then
"riscv64"
else
throw "Unsupported CPU \"${platform.parsed.cpu.name}\"";
alt-arch =
if platform.isx86_64 then
"x64"
else if platform.isAarch64 then
"arm64"
else
platform.parsed.cpu.name;
platform = "${self.os}-${self.arch}";
alt-platform = "${self.os}-${self.alt-arch}";
};
in
self

View File

@@ -0,0 +1,15 @@
{ engine, runCommand }:
runCommand "flutter-engine-${engine.version}-dart"
{
version = engine.dartSdkVersion;
inherit engine;
inherit (engine) outName;
meta = engine.meta // {
description = "Dart SDK compiled from the Flutter Engine";
};
}
''
ln -s ${engine}/out/$outName/dart-sdk $out
''

View File

@@ -0,0 +1,76 @@
{
callPackage,
dartSdkVersion,
flutterVersion,
swiftshaderHash,
swiftshaderRev,
version,
hashes,
url,
patches,
runtimeModes,
isOptimized ? null,
lib,
stdenv,
dart,
mainRuntimeMode ? null,
altRuntimeMode ? null,
}@args:
let
mainRuntimeMode = args.mainRuntimeMode or builtins.elemAt runtimeModes 0;
altRuntimeMode = args.altRuntimeMode or builtins.elemAt runtimeModes 1;
runtimeModesBuilds = lib.genAttrs runtimeModes (
runtimeMode:
callPackage ./package.nix {
inherit
dartSdkVersion
flutterVersion
swiftshaderHash
swiftshaderRev
version
hashes
url
patches
runtimeMode
;
isOptimized = args.isOptimized or runtimeMode != "debug";
}
);
in
stdenv.mkDerivation (
{
pname = "flutter-engine";
inherit url runtimeModes;
inherit (runtimeModesBuilds.${mainRuntimeMode})
meta
src
version
dartSdkVersion
isOptimized
runtimeMode
outName
dart
swiftshader
;
inherit altRuntimeMode;
dontUnpack = true;
dontBuild = true;
installPhase = ''
mkdir -p $out/out
''
+ lib.concatMapStrings (
runtimeMode:
let
runtimeModeBuild = runtimeModesBuilds.${runtimeMode};
runtimeModeOut = runtimeModeBuild.outName;
in
''
ln -sf ${runtimeModeBuild}/out/${runtimeModeOut} $out/out/${runtimeModeOut}
''
) runtimeModes;
}
// runtimeModesBuilds
)

View File

@@ -0,0 +1,364 @@
{
lib,
callPackage,
writeText,
symlinkJoin,
darwin,
clang,
llvm,
tools ? callPackage ./tools.nix {
inherit (stdenv)
hostPlatform
buildPlatform
;
},
stdenv,
stdenvNoCC,
dart,
fetchgit,
runCommand,
llvmPackages,
patchelf,
openbox,
xorg,
libglvnd,
libepoxy,
wayland,
freetype,
pango,
glib,
harfbuzz,
cairo,
gdk-pixbuf,
at-spi2-atk,
zlib,
gtk3,
pkg-config,
ninja,
python312,
gitMinimal,
version,
flutterVersion,
dartSdkVersion,
swiftshaderHash,
swiftshaderRev,
hashes,
patches,
url,
runtimeMode ? "release",
isOptimized ? runtimeMode != "debug",
}:
let
expandSingleDep =
dep: lib.optionals (lib.isDerivation dep) ([ dep ] ++ map (output: dep.${output}) dep.outputs);
expandDeps = deps: lib.flatten (map expandSingleDep deps);
constants = callPackage ./constants.nix { platform = stdenv.targetPlatform; };
python3 = python312;
src = callPackage ./source.nix {
inherit
tools
flutterVersion
version
hashes
url
;
inherit (stdenv)
hostPlatform
buildPlatform
targetPlatform
;
};
swiftshader = fetchgit {
url = "https://swiftshader.googlesource.com/SwiftShader.git";
hash = swiftshaderHash;
rev = swiftshaderRev;
postFetch = ''
rm -rf $out/third_party/llvm-project
'';
};
llvm = symlinkJoin {
name = "llvm";
paths = [
clang
llvmPackages.llvm
];
};
outName = "host_${runtimeMode}${lib.optionalString (!isOptimized) "_unopt"}";
dartPath = "${
if (lib.versionAtLeast flutterVersion "3.23") then "flutter/third_party" else "third_party"
}/dart";
in
stdenv.mkDerivation (finalAttrs: {
pname = "flutter-engine-${runtimeMode}${lib.optionalString (!isOptimized) "-unopt"}";
inherit
version
runtimeMode
patches
isOptimized
dartSdkVersion
src
outName
swiftshader
;
setOutputFlags = false;
doStrip = isOptimized;
toolchain = symlinkJoin {
name = "flutter-engine-toolchain-${version}";
paths =
expandDeps (
lib.optionals (stdenv.hostPlatform.isLinux) [
gtk3
wayland
libepoxy
libglvnd
freetype
at-spi2-atk
glib
gdk-pixbuf
harfbuzz
pango
cairo
xorg.libxcb
xorg.libX11
xorg.libXcursor
xorg.libXrandr
xorg.libXrender
xorg.libXinerama
xorg.libXi
xorg.libXext
xorg.libXfixes
xorg.libXxf86vm
xorg.xorgproto
zlib
]
++ lib.optionals (stdenv.hostPlatform.isDarwin) [
clang
llvm
]
)
++ [
stdenv.cc.libc_dev
stdenv.cc.libc_lib
];
# Needed due to Flutter expecting everything to be relative to $out
# and not true absolute path (ie relative to "/").
postBuild = ''
mkdir -p $(dirname $(dirname "$out/$out"))
ln -s $(dirname "$out") $out/$(dirname "$out")
'';
};
NIX_CFLAGS_COMPILE = [
"-I${finalAttrs.toolchain}/include"
]
++ lib.optional (!isOptimized) "-U_FORTIFY_SOURCE"
++ lib.optionals (lib.versionAtLeast flutterVersion "3.35") [
"-Wno-macro-redefined"
"-Wno-error=macro-redefined"
];
nativeCheckInputs = lib.optionals stdenv.hostPlatform.isLinux [
xorg.xorgserver
openbox
];
nativeBuildInputs = [
(python3.withPackages (
ps: with ps; [
pyyaml
]
))
(tools.vpython python3)
gitMinimal
pkg-config
ninja
dart
]
++ lib.optionals (stdenv.hostPlatform.isLinux) [ patchelf ]
++ lib.optionals (stdenv.hostPlatform.isDarwin) [
darwin.system_cmds
darwin.xcode
tools.xcode-select
]
++ lib.optionals (stdenv.cc.libc ? bin) [ stdenv.cc.libc.bin ];
buildInputs = [ gtk3 ];
patchtools = [ "flutter/third_party/gn/gn" ];
dontPatch = true;
patchgit = [
dartPath
"flutter"
"."
]
++ lib.optional (lib.versionAtLeast flutterVersion "3.21") "flutter/third_party/skia";
postUnpack = ''
pushd ${src.name}
cp ${./pkg-config.py} src/build/config/linux/pkg-config.py
cp -pr --reflink=auto $swiftshader src/flutter/third_party/swiftshader
chmod -R u+w -- src/flutter/third_party/swiftshader
ln -s ${llvmPackages.llvm.monorepoSrc} src/flutter/third_party/swiftshader/third_party/llvm-project
mkdir -p src/flutter/buildtools/${constants.alt-platform}
ln -s ${llvm} src/flutter/buildtools/${constants.alt-platform}/clang
mkdir -p src/buildtools/${constants.alt-platform}
ln -s ${llvm} src/buildtools/${constants.alt-platform}/clang
mkdir -p src/${dartPath}/tools/sdks
ln -s ${dart} src/${dartPath}/tools/sdks/dart-sdk
${lib.optionalString (stdenv.hostPlatform.isLinux) ''
for patchtool in ''${patchtools[@]}; do
patchelf src/$patchtool --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker)
done
''}
for dir in ''${patchgit[@]}; do
pushd src/$dir
rm -rf .git
git init
git add .
git config user.name "nobody"
git config user.email "nobody@local.host"
git commit -a -m "$dir" --quiet
popd
done
dart src/${dartPath}/tools/generate_package_config.dart
echo "${dartSdkVersion}" >src/${dartPath}/sdk/version
rm -rf src/third_party/angle/.git
python3 src/flutter/tools/pub_get_offline.py
pushd src/flutter
for p in ''${patches[@]}; do
patch -p1 -i $p
done
popd
''
# error: 'close_range' is missing exception specification 'noexcept(true)'
+ lib.optionalString (lib.versionAtLeast flutterVersion "3.35") ''
substituteInPlace src/flutter/third_party/dart/runtime/bin/process_linux.cc \
--replace-fail "(unsigned int first, unsigned int last, int flags)" "(unsigned int first, unsigned int last, int flags) noexcept(true)"
''
+ ''
popd
'';
configureFlags = [
"--no-prebuilt-dart-sdk"
"--embedder-for-target"
"--no-goma"
]
++ lib.optionals (stdenv.targetPlatform.isx86_64 == false) [
"--linux"
"--linux-cpu ${constants.alt-arch}"
]
++ lib.optional (!isOptimized) "--unoptimized"
++ lib.optional (runtimeMode == "debug") "--no-stripped"
++ lib.optional finalAttrs.finalPackage.doCheck "--enable-unittests"
++ lib.optional (!finalAttrs.finalPackage.doCheck) "--no-enable-unittests";
# NOTE: Once https://github.com/flutter/flutter/issues/127606 is fixed, use "--no-prebuilt-dart-sdk"
configurePhase = ''
runHook preConfigure
export PYTHONPATH=$src/src/build
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
export PATH=${darwin.xcode}/Contents/Developer/usr/bin/:$PATH
''
+ ''
python3 ./src/flutter/tools/gn $configureFlags \
--runtime-mode $runtimeMode \
--out-dir $out \
--target-sysroot $toolchain \
--target-dir $outName \
--target-triple ${stdenv.targetPlatform.config} \
--enable-fontconfig
runHook postConfigure
'';
buildPhase = ''
runHook preBuild
export TERM=dumb
${lib.optionalString (lib.versionAtLeast flutterVersion "3.29") ''
# ValueError: ZIP does not support timestamps before 1980
substituteInPlace src/flutter/build/zip.py \
--replace-fail "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED)" "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED, strict_timestamps=False)"
''}
ninja -C $out/out/$outName -j$NIX_BUILD_CORES
runHook postBuild
'';
# Tests are broken
doCheck = false;
checkPhase = ''
ln -s $out/out src/out
touch src/out/run_tests.log
sh src/flutter/testing/run_tests.sh $outName
rm src/out/run_tests.log
'';
installPhase = ''
runHook preInstall
rm -rf $out/out/$outName/{obj,exe.unstripped,lib.unstripped,zip_archives}
rm $out/out/$outName/{args.gn,build.ninja,build.ninja.d,compile_commands.json,toolchain.ninja}
find $out/out/$outName -name '*_unittests' -delete
find $out/out/$outName -name '*_benchmarks' -delete
''
+ lib.optionalString (finalAttrs.finalPackage.doCheck) ''
rm $out/out/$outName/{display_list_rendertests,flutter_tester}
''
+ ''
runHook postInstall
'';
passthru = {
dart = callPackage ./dart.nix { engine = finalAttrs.finalPackage; };
};
meta = {
# Very broken on Darwin
broken = stdenv.hostPlatform.isDarwin;
description = "Flutter engine";
homepage = "https://flutter.dev";
maintainers = with lib.maintainers; [ RossComputerGuy ];
license = lib.licenses.bsd3;
platforms = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
}
// lib.optionalAttrs (lib.versionOlder flutterVersion "3.22") { hydraPlatforms = [ ]; };
})

View File

@@ -0,0 +1,247 @@
#!/usr/bin/env python3
#
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import os
import subprocess
import sys
import re
from optparse import OptionParser
# This script runs pkg-config, optionally filtering out some results, and
# returns the result.
#
# The result will be [ <includes>, <cflags>, <libs>, <lib_dirs>, <ldflags> ]
# where each member is itself a list of strings.
#
# You can filter out matches using "-v <regexp>" where all results from
# pkgconfig matching the given regular expression will be ignored. You can
# specify more than one regular expression my specifying "-v" more than once.
#
# You can specify a sysroot using "-s <sysroot>" where sysroot is the absolute
# system path to the sysroot used for compiling. This script will attempt to
# generate correct paths for the sysroot.
#
# When using a sysroot, you must also specify the architecture via
# "-a <arch>" where arch is either "x86" or "x64".
#
# CrOS systemroots place pkgconfig files at <systemroot>/usr/share/pkgconfig
# and one of <systemroot>/usr/lib/pkgconfig or <systemroot>/usr/lib64/pkgconfig
# depending on whether the systemroot is for a 32 or 64 bit architecture. They
# specify the 'lib' or 'lib64' of the pkgconfig path by defining the
# 'system_libdir' variable in the args.gn file. pkg_config.gni communicates this
# variable to this script with the "--system_libdir <system_libdir>" flag. If no
# flag is provided, then pkgconfig files are assumed to come from
# <systemroot>/usr/lib/pkgconfig.
#
# Additionally, you can specify the option --atleast-version. This will skip
# the normal outputting of a dictionary and instead print true or false,
# depending on the return value of pkg-config for the given package.
def SetConfigPath(options):
"""Set the PKG_CONFIG_LIBDIR environment variable.
This takes into account any sysroot and architecture specification from the
options on the given command line.
"""
sysroot = options.sysroot
assert sysroot
# Compute the library path name based on the architecture.
arch = options.arch
if sysroot and not arch:
print("You must specify an architecture via -a if using a sysroot.")
sys.exit(1)
libdir = sysroot + '/' + options.system_libdir + '/pkgconfig'
libdir += ':' + sysroot + '/share/pkgconfig'
os.environ['PKG_CONFIG_LIBDIR'] = libdir
return libdir
def GetPkgConfigPrefixToStrip(options, args):
"""Returns the prefix from pkg-config where packages are installed.
This returned prefix is the one that should be stripped from the beginning of
directory names to take into account sysroots.
"""
# Some sysroots, like the Chromium OS ones, may generate paths that are not
# relative to the sysroot. For example,
# /path/to/chroot/build/x86-generic/usr/lib/pkgconfig/pkg.pc may have all
# paths relative to /path/to/chroot (i.e. prefix=/build/x86-generic/usr)
# instead of relative to /path/to/chroot/build/x86-generic (i.e prefix=/usr).
# To support this correctly, it's necessary to extract the prefix to strip
# from pkg-config's |prefix| variable.
prefix = subprocess.check_output([options.pkg_config,
"--variable=prefix"] + args, env=os.environ).decode('utf-8')
return prefix
def MatchesAnyRegexp(flag, list_of_regexps):
"""Returns true if the first argument matches any regular expression in the
given list."""
for regexp in list_of_regexps:
if regexp.search(flag) != None:
return True
return False
def RewritePath(path, strip_prefix, sysroot):
"""Rewrites a path by stripping the prefix and prepending the sysroot."""
if os.path.isabs(path) and not path.startswith(sysroot):
if path.startswith(strip_prefix):
path = path[len(strip_prefix):]
path = path.lstrip('/')
return os.path.join(sysroot, path)
else:
return path
def main():
# If this is run on non-Linux platforms, just return nothing and indicate
# success. This allows us to "kind of emulate" a Linux build from other
# platforms.
if "linux" not in sys.platform:
print("[[],[],[],[],[]]")
return 0
parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true')
parser.add_option('-p', action='store', dest='pkg_config', type='string',
default='pkg-config')
parser.add_option('-v', action='append', dest='strip_out', type='string')
parser.add_option('-s', action='store', dest='sysroot', type='string')
parser.add_option('-a', action='store', dest='arch', type='string')
parser.add_option('--system_libdir', action='store', dest='system_libdir',
type='string', default='lib')
parser.add_option('--atleast-version', action='store',
dest='atleast_version', type='string')
parser.add_option('--libdir', action='store_true', dest='libdir')
parser.add_option('--dridriverdir', action='store_true', dest='dridriverdir')
parser.add_option('--version-as-components', action='store_true',
dest='version_as_components')
(options, args) = parser.parse_args()
# Make a list of regular expressions to strip out.
strip_out = []
if options.strip_out != None:
for regexp in options.strip_out:
strip_out.append(re.compile(regexp))
if options.sysroot:
libdir = SetConfigPath(options)
if options.debug:
sys.stderr.write('PKG_CONFIG_LIBDIR=%s\n' % libdir)
prefix = GetPkgConfigPrefixToStrip(options, args)
else:
prefix = ''
if options.atleast_version:
# When asking for the return value, just run pkg-config and print the return
# value, no need to do other work.
if not subprocess.call([options.pkg_config,
"--atleast-version=" + options.atleast_version] +
args):
print("true")
else:
print("false")
return 0
if options.version_as_components:
cmd = [options.pkg_config, "--modversion"] + args
try:
version_string = subprocess.check_output(cmd).decode('utf-8')
except:
sys.stderr.write('Error from pkg-config.\n')
return 1
print(json.dumps(list(map(int, version_string.strip().split(".")))))
return 0
if options.libdir:
cmd = [options.pkg_config, "--variable=libdir"] + args
if options.debug:
sys.stderr.write('Running: %s\n' % cmd)
try:
libdir = subprocess.check_output(cmd).decode('utf-8')
except:
print("Error from pkg-config.")
return 1
sys.stdout.write(libdir.strip())
return 0
if options.dridriverdir:
cmd = [options.pkg_config, "--variable=dridriverdir"] + args
if options.debug:
sys.stderr.write('Running: %s\n' % cmd)
try:
dridriverdir = subprocess.check_output(cmd).decode('utf-8')
except:
print("Error from pkg-config.")
return 1
sys.stdout.write(dridriverdir.strip())
return
cmd = [options.pkg_config, "--cflags", "--libs"] + args
if options.debug:
sys.stderr.write('Running: %s\n' % ' '.join(cmd))
try:
flag_string = subprocess.check_output(cmd).decode('utf-8')
except:
sys.stderr.write('Could not run pkg-config.\n')
return 1
# For now just split on spaces to get the args out. This will break if
# pkgconfig returns quoted things with spaces in them, but that doesn't seem
# to happen in practice.
all_flags = flag_string.strip().split(' ')
sysroot = options.sysroot
if not sysroot:
sysroot = ''
includes = []
cflags = []
libs = []
lib_dirs = []
for flag in all_flags[:]:
if len(flag) == 0 or MatchesAnyRegexp(flag, strip_out):
continue;
if flag[:2] == '-l':
libs.append(RewritePath(flag[2:], prefix, sysroot))
elif flag[:2] == '-L':
lib_dirs.append(RewritePath(flag[2:], prefix, sysroot))
elif flag[:2] == '-I':
includes.append(RewritePath(flag[2:], prefix, sysroot))
elif flag[:3] == '-Wl':
# Don't allow libraries to control ld flags. These should be specified
# only in build files.
pass
elif flag == '-pthread':
# Many libs specify "-pthread" which we don't need since we always include
# this anyway. Removing it here prevents a bunch of duplicate inclusions
# on the command line.
pass
else:
cflags.append(flag)
# Output a GN array, the first one is the cflags, the second are the libs. The
# JSON formatter prints GN compatible lists when everything is a list of
# strings.
print(json.dumps([includes, cflags, libs, lib_dirs]))
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,129 @@
{
lib,
callPackage,
fetchgit,
tools ? null,
curl,
pkg-config,
git,
python3,
runCommand,
writeText,
cacert,
flutterVersion,
version,
hashes,
url,
hostPlatform,
targetPlatform,
buildPlatform,
}@pkgs:
let
target-constants = callPackage ./constants.nix { platform = targetPlatform; };
build-constants = callPackage ./constants.nix { platform = buildPlatform; };
tools = pkgs.tools or (callPackage ./tools.nix { inherit hostPlatform buildPlatform; });
boolOption = value: if value then "True" else "False";
in
runCommand "flutter-engine-source-${version}-${buildPlatform.system}-${targetPlatform.system}"
{
pname = "flutter-engine-source";
inherit version;
inherit (tools) depot_tools;
nativeBuildInputs = [
curl
pkg-config
git
tools.cipd
(python3.withPackages (
ps: with ps; [
httplib2
six
]
))
];
gclient = writeText "flutter-engine-${version}.gclient" ''
solutions = [{
"managed": False,
"name": "${lib.optionalString (lib.versionAtLeast flutterVersion "3.29") "engine/"}src/flutter",
"url": "${url}",
"custom_vars": {
"download_fuchsia_deps": False,
"download_android_deps": False,
"download_linux_deps": ${boolOption targetPlatform.isLinux},
"setup_githooks": False,
"download_esbuild": False,
"download_dart_sdk": False,
"host_cpu": "${build-constants.alt-arch}",
"host_os": "${build-constants.alt-os}",
},
}]
target_os_only = True
target_os = [
"${target-constants.alt-os}"
]
target_cpu_only = True
target_cpu = [
"${target-constants.alt-arch}"
]
'';
NIX_SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
DEPOT_TOOLS_UPDATE = "0";
DEPOT_TOOLS_COLLECT_METRICS = "0";
PYTHONDONTWRITEBYTECODE = "1";
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash =
(hashes."${buildPlatform.system}" or { })."${targetPlatform.system}"
or (throw "Hash not set for ${targetPlatform.system} on ${buildPlatform.system}");
}
(
''
source ${../../../../build-support/fetchgit/deterministic-git}
export -f clean_git
export -f make_deterministic_repo
''
+ (
if lib.versionAtLeast flutterVersion "3.29" then
''
mkdir -p source
cp $gclient source/.gclient
cd source
''
else
''
mkdir -p $out
cp $gclient $out/.gclient
cd $out
''
)
+ ''
export PATH=$PATH:$depot_tools
python3 $depot_tools/gclient.py sync --no-history --shallow --nohooks -j $NIX_BUILD_CORES
''
+ lib.optionalString (lib.versionAtLeast flutterVersion "3.29") ''
cp -r engine/src/flutter/third_party/* engine/src/flutter/engine/src/flutter/third_party/
mv engine/src/flutter/engine $out
''
+ ''
find $out -name '.git' -exec rm -rf {} \; || true
rm -rf $out/src/{buildtools,fuchsia}
rm -rf $out/src/flutter/{buildtools,prebuilts,third_party/swiftshader,third_party/gn/.versions}
rm -rf $out/src/flutter/{third_party/dart/tools/sdks/dart-sdk,third_party/ninja/ninja,third_party/java}
rm -rf $out/src/third_party/{dart/tools/sdks/dart-sdk,libcxx/test}
rm -rf $out/.cipd $out/.gclient $out/.gclient_entries $out/.gclient_previous_custom_vars $out/.gclient_previous_sync_commits
''
)

View File

@@ -0,0 +1,97 @@
{
stdenv,
buildPlatform,
hostPlatform,
callPackage,
fetchgit,
fetchurl,
writeText,
runCommand,
darwin,
writeShellScriptBin,
depot_toolsCommit ? "7d95eb2eb054447592585c73a8ff7adad97ecba1",
depot_toolsHash ? "sha256-F7KDuVg11qLKkohIjuXpNdxpnSsT6Z3hE9+wFIG2sSk=",
cipdCommit ? "89ada246fcbf10f330011e4991d017332af2365b",
cipdHashes ? {
"linux-386" = "7f264198598af2ef9d8878349d33c1940f1f3739e46d986962c352ec4cce2690";
"linux-amd64" = "2ada6b46ad1cd1350522c5c05899d273f5c894c7665e30104e7f57084a5aeeb9";
"linux-arm64" = "96eca7e49f6732c50122b94b793c3a5e62ed77bce1686787a8334906791b4168";
"linux-armv6l" = "06394601130652c5e1b055a7e4605c21fc7c6643af0b3b3cac8d2691491afa81";
"linux-mips64" = "f3eda6542b381b7aa8f582698498b0e197972c894590ec35f18faa467c868f5c";
"linux-mips64le" = "74229ada8e2afd9c8e7c58991126869b2880547780d4a197a27c1dfa96851622";
"linux-mipsle" = "2f3c18ec0ad48cd44a9ff39bb60e9afded83ca43fb9c7a5ea9949f6fdd4e1394";
"linux-ppc64" = "79425c0795fb8ba12b39a8856bf7ccb853e85def4317aa6413222f307d4c2dbd";
"linux-ppc64le" = "f9b3d85dde70f1b78cd7a41d2477834c15ac713a59317490a4cdac9f8f092325";
"linux-riscv64" = "bd695164563a66e8d3799e8835f90a398fbae9a4eec24e876c92d5f213943482";
"linux-s390x" = "6f501af80541e733fda23b4208a21ea05919c95d236036a2121e6b6334a2792c";
"macos-amd64" = "41d05580c0014912d6c32619c720646fd136e4557c9c7d7571ecc8c0462733a1";
"macos-arm64" = "dc672bd16d9faf277dd562f1dc00644b10c03c5d838d3cc3d3ea29925d76d931";
"windows-386" = "fa6ed0022a38ffc51ff8a927e3947fe7e59a64b2019dcddca9d3afacf7630444";
"windows-amd64" = "b5423e4b4429837f7fe4d571ce99c068aa0ccb37ddbebc1978a423fd2b0086df";
},
}:
let
constants = callPackage ./constants.nix { platform = buildPlatform; };
host-constants = callPackage ./constants.nix { platform = hostPlatform; };
stdenv-constants = callPackage ./constants.nix { platform = stdenv.hostPlatform; };
in
{
depot_tools = fetchgit {
url = "https://chromium.googlesource.com/chromium/tools/depot_tools.git";
rev = depot_toolsCommit;
hash = depot_toolsHash;
};
cipd =
let
unwrapped =
runCommand "cipd-${cipdCommit}"
{
src = fetchurl {
name = "cipd-${cipdCommit}-unwrapped";
url = "https://chrome-infra-packages.appspot.com/client?platform=${stdenv-constants.platform}&version=git_revision:${cipdCommit}";
sha256 = cipdHashes.${stdenv-constants.platform};
};
}
''
mkdir -p $out/bin
install -m755 $src $out/bin/cipd
'';
in
writeShellScriptBin "cipd" ''
params=$@
if [[ "$1" == "ensure" ]]; then
shift 1
params="ensure"
while [ "$#" -ne 0 ]; do
if [[ "$1" == "-ensure-file" ]]; then
ensureFile="$2"
shift 2
params="$params -ensure-file $ensureFile"
sed -i 's/''${platform}/${host-constants.platform}/g' "$ensureFile"
sed -i 's/gn\/gn\/${stdenv-constants.platform}/gn\/gn\/${constants.platform}/g' "$ensureFile"
if grep flutter/java/openjdk "$ensureFile" >/dev/null; then
sed -i '/src\/flutter\/third_party\/java\/openjdk/,+2 d' "$ensureFile"
fi
else
params="$params $1"
shift 1
fi
done
fi
exec ${unwrapped}/bin/cipd $params
'';
vpython =
pythonPkg:
runCommand "vpython3" { } "mkdir -p $out/bin && ln -s ${pythonPkg}/bin/python $out/bin/vpython3";
xcode-select = writeShellScriptBin "xcode-select" ''
echo ${darwin.xcode}/Contents/Developer
'';
}

View File

@@ -0,0 +1,104 @@
{
lib,
stdenv,
systemPlatform,
buildDartApplication,
runCommand,
writeTextFile,
git,
which,
dart,
version,
flutterSrc,
patches ? [ ],
pubspecLock,
engineVersion,
}:
let
# https://github.com/flutter/flutter/blob/17c92b7ba68ea609f4eb3405211d019c9dbc4d27/engine/src/flutter/tools/engine_tool/test/commands/stamp_command_test.dart#L125
engine_stamp = writeTextFile {
name = "engine_stamp";
text = builtins.toJSON {
build_date = "2025-06-27T12:30:00.000Z";
build_time_ms = 1751027400000;
git_revision = engineVersion;
git_revision_date = "2025-06-27T17:11:53-07:00";
content_hash = "1111111111111111111111111111111111111111";
};
};
dartEntryPoints."flutter_tools.snapshot" = "bin/flutter_tools.dart";
in
buildDartApplication.override { inherit dart; } {
pname = "flutter-tools";
inherit version dartEntryPoints;
dartOutputType = "jit-snapshot";
src = flutterSrc;
sourceRoot = "${flutterSrc.name}/packages/flutter_tools";
postUnpack = ''chmod -R u+w "$NIX_BUILD_TOP/source"'';
inherit patches;
# The given patches are made for the entire SDK source tree.
prePatch = ''pushd "$NIX_BUILD_TOP/source"'';
postPatch = ''
popd
''
# Use arm64 instead of arm64e.
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
substituteInPlace lib/src/ios/xcodeproj.dart \
--replace-fail arm64e arm64
''
# need network
+ lib.optionalString (lib.versionAtLeast version "3.35.0") ''
cp ${engine_stamp} ../../bin/cache/engine_stamp.json
substituteInPlace lib/src/flutter_cache.dart \
--replace-fail "registerArtifact(FlutterEngineStamp(this, logger));" ""
'';
# When the JIT snapshot is being built, the application needs to run.
# It attempts to generate configuration files, and relies on a few external
# tools.
nativeBuildInputs = [
git
which
];
preConfigure = ''
export HOME=.
export FLUTTER_ROOT="$NIX_BUILD_TOP/source"
mkdir -p "$FLUTTER_ROOT/bin/cache"
ln -s '${dart}' "$FLUTTER_ROOT/bin/cache/dart-sdk"
'';
dartCompileFlags = [ "--define=NIX_FLUTTER_HOST_PLATFORM=${systemPlatform}" ];
# The Dart wrapper launchers are useless for the Flutter tool - it is designed
# to be launched from a snapshot by the SDK.
postInstall = ''
pushd "$out"
rm ${builtins.concatStringsSep " " (builtins.attrNames dartEntryPoints)}
popd
'';
sdkSourceBuilders = {
# https://github.com/dart-lang/pub/blob/e1fbda73d1ac597474b82882ee0bf6ecea5df108/lib/src/sdk/dart.dart#L80
"dart" =
name:
runCommand "dart-sdk-${name}" { passthru.packageRoot = "."; } ''
for path in '${dart}/pkg/${name}'; do
if [ -d "$path" ]; then
ln -s "$path" "$out"
break
fi
done
if [ ! -e "$out" ]; then
echo 1>&2 'The Dart SDK does not contain the requested package: ${name}!'
exit 1
fi
'';
};
inherit pubspecLock;
}

View File

@@ -0,0 +1,215 @@
{
useNixpkgsEngine ? false,
version,
engineVersion,
engineHashes ? { },
engineUrl ?
if lib.versionAtLeast version "3.29" then
"https://github.com/flutter/flutter.git@${engineVersion}"
else
"https://github.com/flutter/engine.git@${engineVersion}",
enginePatches ? [ ],
engineRuntimeModes ? [
"release"
"debug"
],
engineSwiftShaderHash,
engineSwiftShaderRev,
patches,
channel,
dart,
src,
pubspecLock,
artifactHashes ? null,
lib,
stdenv,
callPackage,
makeWrapper,
darwin,
gitMinimal,
which,
jq,
flutterTools ? null,
}@args:
let
engine =
if args.useNixpkgsEngine or false then
callPackage ./engine/default.nix {
inherit (args) dart;
dartSdkVersion = args.dart.version;
flutterVersion = version;
swiftshaderRev = engineSwiftShaderRev;
swiftshaderHash = engineSwiftShaderHash;
version = engineVersion;
hashes = engineHashes;
url = engineUrl;
patches = enginePatches;
runtimeModes = engineRuntimeModes;
}
else
null;
dart = if args.useNixpkgsEngine or false then engine.dart else args.dart;
flutterTools =
args.flutterTools or (callPackage ./flutter-tools.nix {
inherit
dart
engineVersion
patches
pubspecLock
version
;
flutterSrc = src;
systemPlatform = stdenv.hostPlatform.system;
});
unwrapped = stdenv.mkDerivation {
name = "flutter-${version}-unwrapped";
inherit src patches version;
nativeBuildInputs = [
makeWrapper
jq
gitMinimal
]
++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.DarwinTools ];
strictDeps = true;
preConfigure = ''
if [ "$(< bin/internal/engine.version)" != '${engineVersion}' ]; then
echo 1>&2 "The given engine version (${engineVersion}) does not match the version required by the Flutter SDK ($(< bin/internal/engine.version))."
exit 1
fi
'';
postPatch = ''
patchShebangs --build ./bin/
patchShebangs packages/flutter_tools/bin
'';
buildPhase = ''
# The flutter_tools package tries to run many Git commands. In most
# cases, unexpected output is handled gracefully, but commands are never
# expected to fail completely. A blank repository needs to be created.
rm -rf .git # Remove any existing Git directory
git init -b nixpkgs
GIT_AUTHOR_NAME=Nixpkgs GIT_COMMITTER_NAME=Nixpkgs \
GIT_AUTHOR_EMAIL= GIT_COMMITTER_EMAIL= \
GIT_AUTHOR_DATE='1/1/1970 00:00:00 +0000' GIT_COMMITTER_DATE='1/1/1970 00:00:00 +0000' \
git commit --allow-empty -m "Initial commit"
(. '${../../../build-support/fetchgit/deterministic-git}'; make_deterministic_repo .)
mkdir -p bin/cache
# Add a flutter_tools artifact stamp, and build a snapshot.
# This is the Flutter CLI application.
echo "$(git rev-parse HEAD)" > bin/cache/flutter_tools.stamp
ln -s '${flutterTools}/share/flutter_tools.snapshot' bin/cache/flutter_tools.snapshot
# Some of flutter_tools's dependencies contain static assets. The
# application attempts to read its own package_config.json to find these
# assets at runtime.
mkdir -p packages/flutter_tools/.dart_tool
ln -s '${flutterTools.pubcache}/package_config.json' packages/flutter_tools/.dart_tool/package_config.json
echo -n "${version}" > version
cat <<EOF > bin/cache/flutter.version.json
{
"devToolsVersion": "$(cat "${dart}/bin/resources/devtools/version.json" | jq -r .version)",
"flutterVersion": "${version}",
"frameworkVersion": "${version}",
"channel": "${channel}",
"repositoryUrl": "https://github.com/flutter/flutter.git",
"frameworkRevision": "nixpkgs000000000000000000000000000000000",
"frameworkCommitDate": "1970-01-01 00:00:00",
"engineRevision": "${engineVersion}",
"dartSdkVersion": "${dart.version}"
}
EOF
# Suppress a small error now that `.gradle`'s location changed.
# Location changed because of the patch "gradle-flutter-tools-wrapper.patch".
mkdir -p "$out/packages/flutter_tools/gradle/.gradle"
'';
installPhase = ''
runHook preInstall
mkdir -p $out
cp -r . $out
rm -rf $out/bin/cache/dart-sdk
ln -sf ${dart} $out/bin/cache/dart-sdk
# The regular launchers are designed to download/build/update SDK
# components, and are not very useful in Nix.
# Replace them with simple links and wrappers.
rm "$out/bin"/{dart,flutter}
ln -s "$out/bin/cache/dart-sdk/bin/dart" "$out/bin/dart"
makeShellWrapper "$out/bin/dart" "$out/bin/flutter" \
--set-default FLUTTER_ROOT "$out" \
--set FLUTTER_ALREADY_LOCKED true \
--add-flags "--disable-dart-dev --packages='${flutterTools.pubcache}/package_config.json' \$NIX_FLUTTER_TOOLS_VM_OPTIONS $out/bin/cache/flutter_tools.snapshot"
runHook postInstall
'';
doInstallCheck = true;
nativeInstallCheckInputs = [
which
]
++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.DarwinTools ];
installCheckPhase = ''
runHook preInstallCheck
export HOME="$(mktemp -d)"
$out/bin/flutter config --android-studio-dir $HOME
$out/bin/flutter config --android-sdk $HOME
$out/bin/flutter --version | fgrep -q '${builtins.substring 0 10 engineVersion}'
runHook postInstallCheck
'';
passthru = {
# TODO: rely on engine.version instead of engineVersion
inherit
dart
engineVersion
artifactHashes
channel
;
tools = flutterTools;
# The derivation containing the original Flutter SDK files.
# When other derivations wrap this one, any unmodified files
# found here should be included as-is, for tooling compatibility.
sdk = unwrapped;
}
// lib.optionalAttrs (engine != null) {
inherit engine;
};
meta = {
broken = (lib.versionOlder version "3.32") && useNixpkgsEngine;
description = "Makes it easy and fast to build beautiful apps for mobile and beyond";
longDescription = ''
Flutter is Google's SDK for crafting beautiful,
fast user experiences for mobile, web, and desktop from a single codebase.
'';
homepage = "https://flutter.dev";
license = lib.licenses.bsd3;
platforms = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
mainProgram = "flutter";
maintainers = with lib.maintainers; [
ericdallo
];
teams = [ lib.teams.flutter ];
};
};
in
unwrapped

View File

@@ -0,0 +1,17 @@
diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
index 5f458bd53e..7a6c59f98d 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
@@ -128,7 +128,11 @@ Future<Depfile> copyAssets(
break;
}
if (doCopy) {
- await (content.file as File).copy(file.path);
+ // Not using File.copy because it preserves permissions.
+ final sourceFile = content.file as File;
+ final destinationFile = file;
+
+ await destinationFile.writeAsBytes(await sourceFile.readAsBytes(), flush: true);
}
} else {
await file.writeAsBytes(await entry.value.contentsAsBytes());

View File

@@ -0,0 +1,12 @@
diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart
index 9134a014f8d..0410f328c66 100644
--- a/packages/flutter_tools/lib/src/base/os.dart
+++ b/packages/flutter_tools/lib/src/base/os.dart
@@ -316,7 +316,6 @@ class _LinuxUtils extends _PosixUtils {
final String osRelease = _fileSystem.file(osReleasePath).readAsStringSync();
prettyName = _getOsReleaseValueForKey(osRelease, prettyNameKey);
} on Exception catch (e) {
- _logger.printTrace('Failed obtaining PRETTY_NAME for Linux: $e');
prettyName = '';
}
try {

View File

@@ -0,0 +1,12 @@
diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart
index 651dc6cf36..236eb370e1 100644
--- a/packages/flutter_tools/lib/src/doctor.dart
+++ b/packages/flutter_tools/lib/src/doctor.dart
@@ -515,7 +515,6 @@ class FlutterValidator extends DoctorValidator {
final String flutterRoot = _flutterRoot();
messages.add(_getFlutterVersionMessage(frameworkVersion, versionChannel, flutterRoot));
- _validateRequiredBinaries(flutterRoot).forEach(messages.add);
messages.add(_getFlutterUpstreamMessage(version));
if (gitUrl != null) {
messages.add(ValidationMessage(_userMessages.flutterGitUrl(gitUrl)));

View File

@@ -0,0 +1,34 @@
From ddb81649092776ecac635af7040685588798b5a5 Mon Sep 17 00:00:00 2001
From: hacker1024 <hacker1024@users.sourceforge.net>
Date: Sun, 27 Aug 2023 22:47:24 +1000
Subject: [PATCH] Allow replacing the Dart binary used for Pub commands with
NIX_FLUTTER_PUB_DART
---
packages/flutter_tools/lib/src/dart/pub.dart | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart
index 40e60f9005..22fd3cebc7 100644
--- a/packages/flutter_tools/lib/src/dart/pub.dart
+++ b/packages/flutter_tools/lib/src/dart/pub.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:io' as io;
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
@@ -544,7 +545,7 @@ class _DefaultPub implements Pub {
List<String> _computePubCommand() {
// TODO(zanderso): refactor to use artifacts.
- final String sdkPath = _fileSystem.path.joinAll(<String>[
+ final String sdkPath = io.Platform.environment['NIX_FLUTTER_PUB_DART'] ?? _fileSystem.path.joinAll(<String>[
Cache.flutterRoot!,
'bin',
'cache',
--
2.41.0

View File

@@ -0,0 +1,21 @@
diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart
index 1ce1951cef..1bd7602318 100644
--- a/packages/flutter_tools/lib/src/base/os.dart
+++ b/packages/flutter_tools/lib/src/base/os.dart
@@ -260,7 +260,15 @@ class _PosixUtils extends OperatingSystemUtils {
@override
String get pathVarSeparator => ':';
- HostPlatform? _hostPlatform;
+ // uname outputs build platform characteristics, not host platform characteristics.
+ // _MacOSUtils uses sysctl instead, which is still incorrect.
+ HostPlatform? _hostPlatform = switch (const String.fromEnvironment('NIX_FLUTTER_HOST_PLATFORM')) {
+ 'x86_64-linux' => HostPlatform.linux_x64,
+ 'aarch64-linux' => HostPlatform.linux_arm64,
+ 'x86_64-darwin' => HostPlatform.darwin_x64,
+ 'aarch64-darwin' => HostPlatform.darwin_arm64,
+ String value => throw ArgumentError.value(value, 'NIX_FLUTTER_HOST_PLATFORM', 'Unknown Nix host platform!'),
+ };
@override
HostPlatform get hostPlatform {

View File

@@ -0,0 +1,13 @@
diff --git a/packages/flutter_tools/lib/src/base/platform.dart b/packages/flutter_tools/lib/src/base/platform.dart
index 45da89ad4c..2d79dbaece 100644
--- a/packages/flutter_tools/lib/src/base/platform.dart
+++ b/packages/flutter_tools/lib/src/base/platform.dart
@@ -132,7 +132,7 @@ class LocalPlatform extends Platform {
String get pathSeparator => io.Platform.pathSeparator;
@override
- String get operatingSystem => io.Platform.operatingSystem;
+ String get operatingSystem => io.Platform.environment['NIX_FLUTTER_OPERATING_SYSTEM'] ?? io.Platform.operatingSystem;
@override
String get operatingSystemVersion => io.Platform.operatingSystemVersion;

View File

@@ -0,0 +1,64 @@
{
symlinkJoin,
makeWrapper,
}:
flutter:
let
self = symlinkJoin {
name = "${flutter.name}-sdk-links";
paths = [
flutter
flutter.cacheDir
flutter.sdk
];
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram "$out/bin/flutter" \
--set-default FLUTTER_ROOT "$out"
# symlinkJoin seems to be missing the .git directory for some reason.
if [ -d '${flutter.sdk}/.git' ]; then
ln -s '${flutter.sdk}/.git' "$out"
fi
# For iOS/macOS builds, *.xcframework/'s from the pre-built
# artifacts are copied into each built app. However, the symlinkJoin
# means that the *.xcframework's contain symlinks into the nix store,
# which causes issues when actually running the apps.
#
# We'll fix this by only linking to an outer *.xcframework dir instead
# of trying to symlinkJoin the files inside the *.xcframework.
artifactsDir="$out/bin/cache/artifacts/engine"
shopt -s globstar
for file in "$artifactsDir"/**/*.xcframework/Info.plist; do
# Get the unwrapped path from the Info.plist inside each .xcframework
origFile="$(readlink -f "$file")"
origFrameworkDir="$(dirname "$origFile")"
# Remove the symlinkJoin .xcframework dir and replace it with a symlink
# to the unwrapped .xcframework dir.
frameworkDir="$(dirname "$file")"
rm -r "$frameworkDir"
ln -s "$origFrameworkDir" "$frameworkDir"
done
shopt -u globstar
'';
passthru = flutter.passthru // {
# Update the SDK attribute.
# This allows any modified SDK files to be included
# in future invocations.
sdk = self;
};
meta = flutter.meta // {
longDescription = ''
${flutter.meta.longDescription}
Modified binaries are linked into the original SDK directory for use with tools that use the whole SDK.
'';
};
};
in
self

View File

@@ -0,0 +1,49 @@
{ callPackage
, flutterPackages
, lib
, symlinkJoin
,
}:
let
nixpkgsRoot = "@nixpkgs_root@";
flutterCompactVersion = "@flutter_compact_version@";
flutterPlatforms = [
"android"
"ios"
"web"
"linux"
"windows"
"macos"
"fuchsia"
"universal"
];
systemPlatforms = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
derivations =
lib.foldl'
(
acc: flutterPlatform:
acc
++ (map
(systemPlatform:
callPackage "${nixpkgsRoot}/pkgs/development/compilers/flutter/artifacts/fetch-artifacts.nix" {
flutter = flutterPackages."v${flutterCompactVersion}";
inherit flutterPlatform;
inherit systemPlatform;
hash = lib.fakeSha256;
})
systemPlatforms)
) [ ]
flutterPlatforms;
in
symlinkJoin {
name = "evaluate-derivations";
paths = derivations;
}

View File

@@ -0,0 +1,27 @@
let
dartVersion = "@dart_version@";
platform = "@platform@";
channel = "@channel@";
in
{
x86_64-linux = { fetchzip }:
fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-linux-x64-release.zip";
sha256 = "0000000000000000000000000000000000000000000000000000";
};
aarch64-linux = { fetchzip }:
fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-linux-arm64-release.zip";
sha256 = "0000000000000000000000000000000000000000000000000000";
};
x86_64-darwin = { fetchzip }:
fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-macos-x64-release.zip";
sha256 = "0000000000000000000000000000000000000000000000000000";
};
aarch64-darwin = { fetchzip }:
fetchzip {
url = "https://storage.googleapis.com/dart-archive/channels/${channel}/release/${dartVersion}/sdk/dartsdk-macos-arm64-release.zip";
sha256 = "0000000000000000000000000000000000000000000000000000";
};
}.${platform}

View File

@@ -0,0 +1,35 @@
{ callPackage, symlinkJoin, stdenv, lib }:
let
nixpkgsRoot = "@nixpkgs_root@";
version = "@flutter_version@";
engineVersion = "@engine_version@";
systemPlatforms = [
"x86_64-linux"
"aarch64-linux"
];
derivations =
lib.foldl'
(
acc: buildPlatform:
acc
++ (map
(targetPlatform:
callPackage "${nixpkgsRoot}/pkgs/development/compilers/flutter/engine/source.nix" {
targetPlatform = lib.systems.elaborate targetPlatform;
hostPlatform = lib.systems.elaborate buildPlatform;
buildPlatform = lib.systems.elaborate buildPlatform;
flutterVersion = version;
version = engineVersion;
url = "https://github.com/flutter/flutter.git@${engineVersion}";
hashes."${buildPlatform}"."${targetPlatform}" = lib.fakeSha256;
})
systemPlatforms)
) [ ]
systemPlatforms;
in
symlinkJoin {
name = "evaluate-derivations";
paths = derivations;
}

View File

@@ -0,0 +1,10 @@
{ fetchgit }:
fetchgit {
url = "https://swiftshader.googlesource.com/SwiftShader.git";
rev = "@engine_swiftshader_rev@";
# Keep with in sync of pkgs/development/compilers/flutter/engine/package.nix
postFetch = ''
rm -rf $out/third_party/llvm-project
'';
}

View File

@@ -0,0 +1,7 @@
{ fetchFromGitHub }:
fetchFromGitHub {
owner = "flutter";
repo = "flutter";
rev = "@flutter_version@";
hash = "@hash@";
}

View File

@@ -0,0 +1,30 @@
{ flutterPackages
, stdenv
, cacert
,
}:
let
flutterCompactVersion = "@flutter_compact_version@";
inherit (flutterPackages."v${flutterCompactVersion}") dart;
in
stdenv.mkDerivation {
name = "pubspec-lock";
src = @flutter_src@;
nativeBuildInputs = [ dart ];
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "@hash@";
buildPhase = ''
cd ./packages/flutter_tools
export HOME="$(mktemp -d)"
dart --root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt pub get -v
'';
installPhase = ''
cp -r ./pubspec.lock $out
'';
}

View File

@@ -0,0 +1,502 @@
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python3Packages.pyyaml
import argparse
import json
import os
import re
import subprocess
import sys
import tempfile
import urllib.request
from pathlib import Path
import yaml
FAKE_HASH = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
NIXPKGS_ROOT = (
subprocess.Popen(
["git", "rev-parse", "--show-toplevel"], stdout=subprocess.PIPE, text=True
)
.communicate()[0]
.strip()
)
def load_code(name, **kwargs):
with Path(
f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/update/{name}.in"
).open("r", encoding="utf-8") as f:
code = f.read()
for key, value in kwargs.items():
code = code.replace(f"@{key}@", value)
return code
# Return out paths
def nix_build(code):
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as temp:
temp.write(code)
temp.flush()
os.fsync(temp.fileno())
temp_name = temp.name
process = subprocess.Popen(
[
"nix-build",
"--impure",
"--no-out-link",
"--expr",
f"with import {NIXPKGS_ROOT} {{}}; callPackage {temp_name} {{}}",
],
stdout=subprocess.PIPE,
text=True,
)
process.wait()
Path(temp_name).unlink() # Clean up the temporary file
return process.stdout.read().strip().splitlines()[0]
# Return errors
def nix_build_to_fail(code):
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as temp:
temp.write(code)
temp.flush()
os.fsync(temp.fileno())
temp_name = temp.name
process = subprocess.Popen(
[
"nix-build",
"--impure",
"--keep-going",
"--no-link",
"--expr",
f"with import {NIXPKGS_ROOT} {{}}; callPackage {temp_name} {{}}",
],
stderr=subprocess.PIPE,
text=True,
)
stderr = ""
while True:
line = process.stderr.readline()
if not line:
break
stderr += line
print(line.strip())
process.wait()
Path(temp_name).unlink() # Clean up the temporary file
return stderr
def get_engine_hashes(engine_version, flutter_version):
code = load_code(
"get-engine-hashes.nix",
nixpkgs_root=NIXPKGS_ROOT,
flutter_version=flutter_version,
engine_version=engine_version,
)
stderr = nix_build_to_fail(code)
pattern = re.compile(
rf"/nix/store/.*-flutter-engine-source-{engine_version}-(.+?-.+?)-(.+?-.+?).drv':\n\s+specified: .*\n\s+got:\s+(.+?)\n"
)
matches = pattern.findall(stderr)
result_dict = {}
for match in matches:
flutter_platform, architecture, got = match
result_dict.setdefault(flutter_platform, {})[architecture] = got
def sort_dict_recursive(d):
return {
k: sort_dict_recursive(v) if isinstance(v, dict) else v
for k, v in sorted(d.items())
}
return sort_dict_recursive(result_dict)
def get_artifact_hashes(flutter_compact_version):
code = load_code(
"get-artifact-hashes.nix",
nixpkgs_root=NIXPKGS_ROOT,
flutter_compact_version=flutter_compact_version,
)
stderr = nix_build_to_fail(code)
pattern = re.compile(
r"/nix/store/.*-flutter-artifacts-(.+?)-(.+?).drv':\n\s+specified: .*\n\s+got:\s+(.+?)\n"
)
matches = pattern.findall(stderr)
result_dict = {}
for match in matches:
flutter_platform, architecture, got = match
result_dict.setdefault(flutter_platform, {})[architecture] = got
def sort_dict_recursive(d):
return {
k: sort_dict_recursive(v) if isinstance(v, dict) else v
for k, v in sorted(d.items())
}
return sort_dict_recursive(result_dict)
def get_dart_hashes(dart_version, channel):
platforms = ["x86_64-linux", "aarch64-linux", "x86_64-darwin", "aarch64-darwin"]
result_dict = {}
for platform in platforms:
code = load_code(
"get-dart-hashes.nix",
dart_version=dart_version,
channel=channel,
platform=platform,
)
stderr = nix_build_to_fail(code)
pattern = re.compile(r"got:\s+(.+?)\n")
result_dict[platform] = pattern.findall(stderr)[0]
return result_dict
def get_flutter_hash_and_src(flutter_version):
code = load_code("get-flutter.nix", flutter_version=flutter_version, hash="")
stderr = nix_build_to_fail(code)
pattern = re.compile(r"got:\s+(.+?)\n")
flutter_hash_value = pattern.findall(stderr)[0]
code = load_code(
"get-flutter.nix", flutter_version=flutter_version, hash=flutter_hash_value
)
return (flutter_hash_value, nix_build(code))
def get_pubspec_lock(flutter_compact_version, flutter_src):
code = load_code(
"get-pubspec-lock.nix",
flutter_compact_version=flutter_compact_version,
flutter_src=flutter_src,
hash="",
)
stderr = nix_build_to_fail(code)
pattern = re.compile(r"got:\s+(.+?)\n")
pubspec_lock_hash = pattern.findall(stderr)[0]
code = load_code(
"get-pubspec-lock.nix",
flutter_compact_version=flutter_compact_version,
flutter_src=flutter_src,
hash=pubspec_lock_hash,
)
pubspec_lock_file = nix_build(code)
with Path(pubspec_lock_file).open("r", encoding="utf-8") as f:
pubspec_lock_yaml = f.read()
return yaml.safe_load(pubspec_lock_yaml)
def get_engine_swiftshader_rev(engine_version):
with urllib.request.urlopen(
f"https://github.com/flutter/flutter/raw/{engine_version}/DEPS"
) as f:
deps = f.read().decode("utf-8")
pattern = re.compile(
r"Var\('swiftshader_git'\) \+ '\/SwiftShader\.git' \+ '@' \+ \'([0-9a-fA-F]{40})\'\,"
)
return pattern.findall(deps)[0]
def get_engine_swiftshader_hash(engine_swiftshader_rev):
code = load_code(
"get-engine-swiftshader.nix",
engine_swiftshader_rev=engine_swiftshader_rev,
hash="",
)
stderr = nix_build_to_fail(code)
pattern = re.compile(r"got:\s+(.+?)\n")
return pattern.findall(stderr)[0]
def write_data(
nixpkgs_flutter_version_directory,
flutter_version,
channel,
engine_hash,
engine_hashes,
engine_swiftshader_hash,
engine_swiftshader_rev,
dart_version,
dart_hash,
flutter_hash,
artifact_hashes,
pubspec_lock,
):
with Path(f"{nixpkgs_flutter_version_directory}/data.json").open(
"w", encoding="utf-8"
) as f:
f.write(
json.dumps(
{
"version": flutter_version,
"engineVersion": engine_hash,
"engineSwiftShaderHash": engine_swiftshader_hash,
"engineSwiftShaderRev": engine_swiftshader_rev,
"channel": channel,
"engineHashes": engine_hashes,
"dartVersion": dart_version,
"dartHash": dart_hash,
"flutterHash": flutter_hash,
"artifactHashes": artifact_hashes,
"pubspecLock": pubspec_lock,
},
indent=2,
).strip()
+ "\n"
)
def update_all_packages():
versions_directory = f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/versions"
versions = [d.name for d in Path(versions_directory).iterdir()]
versions = sorted(
versions,
key=lambda x: (int(x.split("_")[0]), int(x.split("_")[1])),
reverse=True,
)
new_content = [
"flutterPackages-bin = recurseIntoAttrs (callPackage ../development/compilers/flutter { });",
"flutterPackages-source = recurseIntoAttrs (",
" callPackage ../development/compilers/flutter { useNixpkgsEngine = true; }",
");",
"flutterPackages = flutterPackages-bin;",
"flutter = flutterPackages.stable;",
] + [
f"flutter{version.replace('_', '')} = flutterPackages.v{version};"
for version in versions
]
with Path(f"{NIXPKGS_ROOT}/pkgs/top-level/all-packages.nix").open(
"r", encoding="utf-8"
) as file:
lines = file.read().splitlines(keepends=True)
start = -1
end = -1
for i, line in enumerate(lines):
if (
"flutterPackages-bin = recurseIntoAttrs (callPackage ../development/compilers/flutter { });"
in line
):
start = i
if start != -1 and len(line.strip()) == 0:
end = i
break
if start != -1 and end != -1:
del lines[start:end]
lines[start:start] = [f" {line}\n" for line in new_content]
with Path(f"{NIXPKGS_ROOT}/pkgs/top-level/all-packages.nix").open(
"w", encoding="utf-8"
) as file:
file.write("".join(lines))
# Finds Flutter version, Dart version, and Engine hash.
# If the Flutter version is given, it uses that. Otherwise finds the
# latest stable Flutter version.
def find_versions(flutter_version=None, channel=None):
engine_hash = None
dart_version = None
releases = json.load(
urllib.request.urlopen(
"https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json"
)
)
if not channel:
channel = "stable"
if not flutter_version:
release_hash = releases["current_release"][channel]
release = next(
filter(
lambda release: release["hash"] == release_hash, releases["releases"]
)
)
flutter_version = release["version"]
tags = (
subprocess.Popen(
["git", "ls-remote", "--tags", "https://github.com/flutter/flutter.git"],
stdout=subprocess.PIPE,
text=True,
)
.communicate()[0]
.strip()
)
try:
flutter_hash = (
next(
filter(
lambda line: line.endswith(f"refs/tags/{flutter_version}"),
tags.splitlines(),
)
)
.split("refs")[0]
.strip()
)
engine_hash = (
urllib.request.urlopen(
f"https://github.com/flutter/flutter/raw/{flutter_hash}/bin/internal/engine.version"
)
.read()
.decode("utf-8")
.strip()
)
except StopIteration:
sys.exit(f"Couldn't find Engine hash for Flutter version: {flutter_version}")
try:
dart_version = next(
filter(
lambda release: release["version"] == flutter_version,
releases["releases"],
)
)["dart_sdk_version"]
if " " in dart_version:
dart_version = dart_version.split(" ")[2][:-1]
except StopIteration:
sys.exit(f"Couldn't find Dart version for Flutter version: {flutter_version}")
return (flutter_version, engine_hash, dart_version, channel)
def main():
parser = argparse.ArgumentParser(description="Update Flutter in Nixpkgs")
parser.add_argument("--version", type=str, help="Specify Flutter version")
parser.add_argument("--channel", type=str, help="Specify Flutter release channel")
parser.add_argument(
"--artifact-hashes", action="store_true", help="Whether to get artifact hashes"
)
args = parser.parse_args()
(flutter_version, engine_hash, dart_version, channel) = find_versions(
args.version, args.channel
)
flutter_compact_version = "_".join(flutter_version.split(".")[:2])
if args.artifact_hashes:
print(
json.dumps(get_artifact_hashes(flutter_compact_version), indent=2).strip()
+ "\n"
)
return
print(
f"Flutter version: {flutter_version} ({flutter_compact_version}) on ({channel})"
)
print(f"Engine hash: {engine_hash}")
print(f"Dart version: {dart_version}")
dart_hash = get_dart_hashes(dart_version, channel)
(flutter_hash, flutter_src) = get_flutter_hash_and_src(flutter_version)
nixpkgs_flutter_version_directory = f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/versions/{flutter_compact_version}"
if Path(f"{nixpkgs_flutter_version_directory}/data.json").exists():
Path(f"{nixpkgs_flutter_version_directory}/data.json").unlink()
Path(nixpkgs_flutter_version_directory).mkdir(parents=True, exist_ok=True)
update_all_packages()
common_data_args = {
"nixpkgs_flutter_version_directory": nixpkgs_flutter_version_directory,
"flutter_version": flutter_version,
"channel": channel,
"dart_version": dart_version,
"engine_hash": engine_hash,
"flutter_hash": flutter_hash,
"dart_hash": dart_hash,
}
write_data(
pubspec_lock={},
artifact_hashes={},
engine_hashes={},
engine_swiftshader_hash=FAKE_HASH,
engine_swiftshader_rev="0",
**common_data_args,
)
pubspec_lock = get_pubspec_lock(flutter_compact_version, flutter_src)
write_data(
pubspec_lock=pubspec_lock,
artifact_hashes={},
engine_hashes={},
engine_swiftshader_hash=FAKE_HASH,
engine_swiftshader_rev="0",
**common_data_args,
)
artifact_hashes = get_artifact_hashes(flutter_compact_version)
write_data(
pubspec_lock=pubspec_lock,
artifact_hashes=artifact_hashes,
engine_hashes={},
engine_swiftshader_hash=FAKE_HASH,
engine_swiftshader_rev="0",
**common_data_args,
)
engine_hashes = get_engine_hashes(engine_hash, flutter_version)
write_data(
pubspec_lock=pubspec_lock,
artifact_hashes=artifact_hashes,
engine_hashes=engine_hashes,
engine_swiftshader_hash=FAKE_HASH,
engine_swiftshader_rev="0",
**common_data_args,
)
engine_swiftshader_rev = get_engine_swiftshader_rev(engine_hash)
engine_swiftshader_hash = get_engine_swiftshader_hash(engine_swiftshader_rev)
write_data(
pubspec_lock=pubspec_lock,
artifact_hashes=artifact_hashes,
engine_hashes=engine_hashes,
engine_swiftshader_hash=engine_swiftshader_hash,
engine_swiftshader_rev=engine_swiftshader_rev,
**common_data_args,
)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index 252021cf78..e50ef0885d 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -51,14 +51,6 @@ class FlutterCache extends Cache {
registerArtifact(IosUsbArtifacts(artifactName, this, platform: platform));
}
registerArtifact(FontSubsetArtifacts(this, platform: platform));
- registerArtifact(PubDependencies(
- logger: logger,
- // flutter root and pub must be lazily initialized to avoid accessing
- // before the version is determined.
- flutterRoot: () => Cache.flutterRoot!,
- pub: () => pub,
- projectFactory: projectFactory,
- ));
}
}

View File

@@ -0,0 +1,30 @@
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index e4e474ab6e..5548599802 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1693,7 +1693,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
- if (shouldUpdateCache) {
+ if (false) {
// First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`.
final bool offline;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 50783f8435..db94062840 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -377,11 +377,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.analytics.suppressTelemetry();
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag = topLevelResults[FlutterGlobalOptions.kMachineFlag] as bool? ?? false;
- if (await _shouldCheckForUpdates(topLevelResults, topLevelMachineFlag: machineFlag)) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
// See if the user specified a specific device.
final String? specifiedDeviceId = topLevelResults[FlutterGlobalOptions.kDeviceIdOption] as String?;

View File

@@ -0,0 +1,69 @@
From 6df275df3b8694daf16302b407520e3b1dee6724 Mon Sep 17 00:00:00 2001
From: Philip Hayes <philiphayes9@gmail.com>
Date: Thu, 12 Sep 2024 13:23:00 -0700
Subject: [PATCH] fix: cleanup xcode_backend.sh to fix iOS build w/
`NixOS/nixpkgs` flutter
This patch cleans up `xcode_backend.sh`. It now effectively just runs
`exec $FLUTTER_ROOT/bin/dart ./xcode_backend.dart`.
The previous `xcode_backend.sh` tries to discover `$FLUTTER_ROOT` from
argv[0], even though its presence is already guaranteed (the wrapped
`xcode_backend.dart` also relies on this env).
When using nixpkgs flutter, the flutter SDK directory is composed of several
layers, joined together using symlinks (called a `symlinkJoin`). Without this
patch, the auto-discover traverses the symlinks into the wrong layer, and so it
uses an "unwrapped" `dart` command instead of a "wrapped" dart that sets some
important envs/flags (like `$FLUTTER_ROOT`).
Using the "unwrapped" dart then manifests in this error when compiling, since
it doesn't see the ios build-support artifacts:
```
$ flutter run -d iphone
Running Xcode build...
Xcode build done. 6.4s
Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.24.1-unwrapped/bin/cache/artifacts".
```
---
packages/flutter_tools/bin/xcode_backend.sh | 25 ++++-----------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 2889d7c8e4..48b9d06c6e 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -6,24 +6,7 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
-
-"$DART" "$BIN_DIR/xcode_backend.dart" "$@"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="${BASH_SOURCE[0]%.sh}.dart"
+exec "${dart}" "${xcode_backend_dart}" "$@"
--
2.46.0

View File

@@ -0,0 +1,44 @@
This patch introduces an intermediate Gradle build step to alter the behavior
of flutter_tools' Gradle project, specifically moving the creation of `build`
and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`.
Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle`
directories within the Nix Store. Resulting in read-only errors when trying to build a
Flutter Android app at runtime.
This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project
when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")`
`rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory.
The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it.
This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting
`rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`.
Now the `.gradle` will be built in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, but `build` doesn't.
To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` as well, we need to set `buildDirectory`.
diff --git a/packages/flutter_tools/gradle/settings.gradle b/packages/flutter_tools/gradle/settings.gradle
new file mode 100644
index 0000000000..b2485c94b4
--- /dev/null
+++ b/packages/flutter_tools/gradle/settings.gradle
@@ -0,0 +1,19 @@
+rootProject.buildFileName = "/dev/null"
+
+def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
+def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
+dir.mkdirs()
+def file = new File(dir, "settings.gradle")
+
+file.text = """
+rootProject.projectDir = new File("$settingsDir")
+apply from: new File("$settingsDir/settings.gradle.kts")
+
+gradle.allprojects { project ->
+ project.beforeEvaluate {
+ project.layout.buildDirectory = new File("$dir/build")
+ }
+}
+"""
+
+includeBuild(dir)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index 252021cf78..e50ef0885d 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -51,14 +51,6 @@ class FlutterCache extends Cache {
registerArtifact(IosUsbArtifacts(artifactName, this, platform: platform));
}
registerArtifact(FontSubsetArtifacts(this, platform: platform));
- registerArtifact(PubDependencies(
- logger: logger,
- // flutter root and pub must be lazily initialized to avoid accessing
- // before the version is determined.
- flutterRoot: () => Cache.flutterRoot!,
- pub: () => pub,
- projectFactory: projectFactory,
- ));
}
}

View File

@@ -0,0 +1,30 @@
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index e4e474ab6e..5548599802 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1693,7 +1693,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
- if (shouldUpdateCache) {
+ if (false) {
// First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`.
final bool offline;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 50783f8435..db94062840 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -377,11 +377,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.analytics.suppressTelemetry();
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag = topLevelResults[FlutterGlobalOptions.kMachineFlag] as bool? ?? false;
- if (await _shouldCheckForUpdates(topLevelResults, topLevelMachineFlag: machineFlag)) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
// See if the user specified a specific device.
final String? specifiedDeviceId = topLevelResults[FlutterGlobalOptions.kDeviceIdOption] as String?;

View File

@@ -0,0 +1,69 @@
From 6df275df3b8694daf16302b407520e3b1dee6724 Mon Sep 17 00:00:00 2001
From: Philip Hayes <philiphayes9@gmail.com>
Date: Thu, 12 Sep 2024 13:23:00 -0700
Subject: [PATCH] fix: cleanup xcode_backend.sh to fix iOS build w/
`NixOS/nixpkgs` flutter
This patch cleans up `xcode_backend.sh`. It now effectively just runs
`exec $FLUTTER_ROOT/bin/dart ./xcode_backend.dart`.
The previous `xcode_backend.sh` tries to discover `$FLUTTER_ROOT` from
argv[0], even though its presence is already guaranteed (the wrapped
`xcode_backend.dart` also relies on this env).
When using nixpkgs flutter, the flutter SDK directory is composed of several
layers, joined together using symlinks (called a `symlinkJoin`). Without this
patch, the auto-discover traverses the symlinks into the wrong layer, and so it
uses an "unwrapped" `dart` command instead of a "wrapped" dart that sets some
important envs/flags (like `$FLUTTER_ROOT`).
Using the "unwrapped" dart then manifests in this error when compiling, since
it doesn't see the ios build-support artifacts:
```
$ flutter run -d iphone
Running Xcode build...
Xcode build done. 6.4s
Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.24.1-unwrapped/bin/cache/artifacts".
```
---
packages/flutter_tools/bin/xcode_backend.sh | 25 ++++-----------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 2889d7c8e4..48b9d06c6e 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -6,24 +6,7 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
-
-"$DART" "$BIN_DIR/xcode_backend.dart" "$@"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="${BASH_SOURCE[0]%.sh}.dart"
+exec "${dart}" "${xcode_backend_dart}" "$@"
--
2.46.0

View File

@@ -0,0 +1,44 @@
This patch introduces an intermediate Gradle build step to alter the behavior
of flutter_tools' Gradle project, specifically moving the creation of `build`
and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`.
Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle`
directories within the Nix Store. Resulting in read-only errors when trying to build a
Flutter Android app at runtime.
This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project
when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")`
`rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory.
The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it.
This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting
`rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`.
Now the `.gradle` will be built in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, but `build` doesn't.
To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` as well, we need to set `buildDirectory`.
diff --git a/packages/flutter_tools/gradle/settings.gradle b/packages/flutter_tools/gradle/settings.gradle
new file mode 100644
index 0000000000..b2485c94b4
--- /dev/null
+++ b/packages/flutter_tools/gradle/settings.gradle
@@ -0,0 +1,19 @@
+rootProject.buildFileName = "/dev/null"
+
+def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
+def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
+dir.mkdirs()
+def file = new File(dir, "settings.gradle")
+
+file.text = """
+rootProject.projectDir = new File("$settingsDir")
+apply from: new File("$settingsDir/settings.gradle.kts")
+
+gradle.allprojects { project ->
+ project.beforeEvaluate {
+ project.layout.buildDirectory = new File("$dir/build")
+ }
+}
+"""
+
+includeBuild(dir)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index df67547..eacc7c4 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -51,16 +51,6 @@ class FlutterCache extends Cache {
registerArtifact(IosUsbArtifacts(artifactName, this, platform: platform));
}
registerArtifact(FontSubsetArtifacts(this, platform: platform));
- registerArtifact(
- PubDependencies(
- logger: logger,
- // flutter root and pub must be lazily initialized to avoid accessing
- // before the version is determined.
- flutterRoot: () => Cache.flutterRoot!,
- pub: () => pub,
- projectFactory: projectFactory,
- ),
- );
}
}

View File

@@ -0,0 +1,30 @@
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index e4e474ab6e..5548599802 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1693,7 +1693,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
- if (shouldUpdateCache) {
+ if (false) {
// First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`.
final bool offline;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index a1104da..1749d65 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -444,12 +444,8 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.analytics.suppressTelemetry();
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag =
topLevelResults[FlutterGlobalOptions.kMachineFlag] as bool? ?? false;
- if (await _shouldCheckForUpdates(topLevelResults, topLevelMachineFlag: machineFlag)) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
// See if the user specified a specific device.
final String? specifiedDeviceId =

View File

@@ -0,0 +1,69 @@
From 6df275df3b8694daf16302b407520e3b1dee6724 Mon Sep 17 00:00:00 2001
From: Philip Hayes <philiphayes9@gmail.com>
Date: Thu, 12 Sep 2024 13:23:00 -0700
Subject: [PATCH] fix: cleanup xcode_backend.sh to fix iOS build w/
`NixOS/nixpkgs` flutter
This patch cleans up `xcode_backend.sh`. It now effectively just runs
`exec $FLUTTER_ROOT/bin/dart ./xcode_backend.dart`.
The previous `xcode_backend.sh` tries to discover `$FLUTTER_ROOT` from
argv[0], even though its presence is already guaranteed (the wrapped
`xcode_backend.dart` also relies on this env).
When using nixpkgs flutter, the flutter SDK directory is composed of several
layers, joined together using symlinks (called a `symlinkJoin`). Without this
patch, the auto-discover traverses the symlinks into the wrong layer, and so it
uses an "unwrapped" `dart` command instead of a "wrapped" dart that sets some
important envs/flags (like `$FLUTTER_ROOT`).
Using the "unwrapped" dart then manifests in this error when compiling, since
it doesn't see the ios build-support artifacts:
```
$ flutter run -d iphone
Running Xcode build...
Xcode build done. 6.4s
Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.24.1-unwrapped/bin/cache/artifacts".
```
---
packages/flutter_tools/bin/xcode_backend.sh | 25 ++++-----------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 2889d7c8e4..48b9d06c6e 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -6,24 +6,7 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
-
-"$DART" "$BIN_DIR/xcode_backend.dart" "$@"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="${BASH_SOURCE[0]%.sh}.dart"
+exec "${dart}" "${xcode_backend_dart}" "$@"
--
2.46.0

View File

@@ -0,0 +1,220 @@
This patch introduces an intermediate Gradle build step to alter the behavior
of flutter_tools' Gradle project, specifically moving the creation of `build`
and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`.
Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle`
directories within the Nix Store. Resulting in read-only errors when trying to build a
Flutter Android app at runtime.
This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project
when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")`
`rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory.
The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it.
This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting
`rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`.
To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, we need to set `buildDirectory`.
To move `.gradle` as well, the `--project-cache-dir` argument must be passed to the Gradle wrapper.
Changing the `GradleUtils.getExecutable` function signature is a delibarate choice, to ensure that no new unpatched usages slip in.
--- /dev/null
+++ b/packages/flutter_tools/gradle/settings.gradle
@@ -0,0 +1,19 @@
+rootProject.buildFileName = "/dev/null"
+
+def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
+def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
+dir.mkdirs()
+def file = new File(dir, "settings.gradle")
+
+file.text = """
+rootProject.projectDir = new File("$settingsDir")
+apply from: new File("$settingsDir/settings.gradle.kts")
+
+gradle.allprojects { project ->
+ project.beforeEvaluate {
+ project.layout.buildDirectory = new File("$dir/build")
+ }
+}
+"""
+
+includeBuild(dir)
--- a/packages/flutter_tools/gradle/build.gradle.kts
+++ b/packages/flutter_tools/gradle/build.gradle.kts
@@ -4,6 +4,11 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+// While flutter_tools runs Gradle with a --project-cache-dir, this startParameter
+// is not passed correctly to the Kotlin Gradle plugin for some reason, and so
+// must be set here as well.
+gradle.startParameter.projectCacheDir = layout.buildDirectory.dir("cache").get().asFile
+
plugins {
`java-gradle-plugin`
groovy
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -456,9 +456,9 @@ class AndroidGradleBuilder implements AndroidBuilder {
// from the local.properties file.
updateLocalProperties(project: project, buildInfo: androidBuildInfo.buildInfo);
- final List<String> options = <String>[];
-
- final String gradleExecutablePath = _gradleUtils.getExecutable(project);
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
// All automatically created files should exist.
if (configOnly) {
@@ -781,7 +781,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
'aar_init_script.gradle',
);
final List<String> command = <String>[
- _gradleUtils.getExecutable(project),
+ ..._gradleUtils.getExecutable(project),
'-I=$initScript',
'-Pflutter-root=$flutterRoot',
'-Poutput-dir=${outputDirectory.path}',
@@ -896,6 +896,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
final List<String> results = <String>[];
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
_kBuildVariantTaskName,
preRunTask: () {
@@ -911,10 +915,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: const <String>['-q'],
+ options: <String>[...options, '-q'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
outputParser: (String line) {
if (_kBuildVariantRegex.firstMatch(line) case final RegExpMatch match) {
results.add(match.namedGroup(_kBuildVariantRegexGroupName)!);
@@ -948,6 +952,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
late Stopwatch sw;
int exitCode = 1;
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
taskName,
preRunTask: () {
@@ -963,10 +971,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: <String>['-q', '-PoutputPath=$outputPath'],
+ options: <String>[...options, '-q', '-PoutputPath=$outputPath'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
);
} on Error catch (error) {
_logger.printError(error.toString());
--- a/packages/flutter_tools/lib/src/android/gradle_errors.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart
@@ -240,7 +240,12 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
required bool usesAndroidX,
}) async {
final RunResult tasksRunResult = await globals.processUtils.run(
- <String>[globals.gradleUtils!.getExecutable(project), 'app:tasks', '--all', '--console=auto'],
+ <String>[
+ ...globals.gradleUtils!.getExecutable(project),
+ 'app:tasks',
+ '--all',
+ '--console=auto',
+ ],
throwOnError: true,
workingDirectory: project.android.hostAppGradleRoot.path,
environment: globals.java?.environment,
--- a/packages/flutter_tools/lib/src/android/gradle_utils.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:meta/meta.dart';
+import 'package:path/path.dart';
import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
@@ -154,9 +155,29 @@ class GradleUtils {
final Logger _logger;
final OperatingSystemUtils _operatingSystemUtils;
+ List<String> get _requiredArguments {
+ final String cacheDir = join(
+ switch (globals.platform.environment['XDG_CACHE_HOME']) {
+ final String cacheHome => cacheHome,
+ _ => join(
+ globals.fsUtils.homeDirPath ?? throwToolExit('No cache directory has been specified.'),
+ '.cache',
+ ),
+ },
+ 'flutter',
+ 'nix-flutter-tools-gradle',
+ globals.flutterVersion.engineRevision.substring(0, 10),
+ );
+
+ return <String>[
+ '--project-cache-dir=${join(cacheDir, 'cache')}',
+ '-Pkotlin.project.persistent.dir=${join(cacheDir, 'kotlin')}',
+ ];
+ }
+
/// Gets the Gradle executable path and prepares the Gradle project.
/// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
- String getExecutable(FlutterProject project) {
+ List<String> getExecutable(FlutterProject project) {
final Directory androidDir = project.android.hostAppGradleRoot;
injectGradleWrapperIfNeeded(androidDir);
@@ -167,7 +188,7 @@ class GradleUtils {
// If the Gradle executable doesn't have execute permission,
// then attempt to set it.
_operatingSystemUtils.makeExecutable(gradle);
- return gradle.absolute.path;
+ return <String>[gradle.absolute.path, ..._requiredArguments];
}
throwToolExit(
'Unable to locate gradlew script. Please check that ${gradle.path} '
--- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
@@ -2740,8 +2740,8 @@ Gradle Crashed
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}
--- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
@@ -1580,8 +1580,8 @@ Platform fakePlatform(String name) {
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index df67547..eacc7c4 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -51,16 +51,6 @@ class FlutterCache extends Cache {
registerArtifact(IosUsbArtifacts(artifactName, this, platform: platform));
}
registerArtifact(FontSubsetArtifacts(this, platform: platform));
- registerArtifact(
- PubDependencies(
- logger: logger,
- // flutter root and pub must be lazily initialized to avoid accessing
- // before the version is determined.
- flutterRoot: () => Cache.flutterRoot!,
- pub: () => pub,
- projectFactory: projectFactory,
- ),
- );
}
}

View File

@@ -0,0 +1,30 @@
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index e4e474ab6e..5548599802 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1693,7 +1693,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
- if (shouldUpdateCache) {
+ if (false) {
// First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`.
final bool offline;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index a1104da..1749d65 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -444,12 +444,8 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.analytics.suppressTelemetry();
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag =
topLevelResults[FlutterGlobalOptions.kMachineFlag] as bool? ?? false;
- if (await _shouldCheckForUpdates(topLevelResults, topLevelMachineFlag: machineFlag)) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
// See if the user specified a specific device.
final String? specifiedDeviceId =

View File

@@ -0,0 +1,69 @@
From 6df275df3b8694daf16302b407520e3b1dee6724 Mon Sep 17 00:00:00 2001
From: Philip Hayes <philiphayes9@gmail.com>
Date: Thu, 12 Sep 2024 13:23:00 -0700
Subject: [PATCH] fix: cleanup xcode_backend.sh to fix iOS build w/
`NixOS/nixpkgs` flutter
This patch cleans up `xcode_backend.sh`. It now effectively just runs
`exec $FLUTTER_ROOT/bin/dart ./xcode_backend.dart`.
The previous `xcode_backend.sh` tries to discover `$FLUTTER_ROOT` from
argv[0], even though its presence is already guaranteed (the wrapped
`xcode_backend.dart` also relies on this env).
When using nixpkgs flutter, the flutter SDK directory is composed of several
layers, joined together using symlinks (called a `symlinkJoin`). Without this
patch, the auto-discover traverses the symlinks into the wrong layer, and so it
uses an "unwrapped" `dart` command instead of a "wrapped" dart that sets some
important envs/flags (like `$FLUTTER_ROOT`).
Using the "unwrapped" dart then manifests in this error when compiling, since
it doesn't see the ios build-support artifacts:
```
$ flutter run -d iphone
Running Xcode build...
Xcode build done. 6.4s
Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.24.1-unwrapped/bin/cache/artifacts".
```
---
packages/flutter_tools/bin/xcode_backend.sh | 25 ++++-----------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 2889d7c8e4..48b9d06c6e 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -6,24 +6,7 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
-
-"$DART" "$BIN_DIR/xcode_backend.dart" "$@"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="${BASH_SOURCE[0]%.sh}.dart"
+exec "${dart}" "${xcode_backend_dart}" "$@"
--
2.46.0

View File

@@ -0,0 +1,220 @@
This patch introduces an intermediate Gradle build step to alter the behavior
of flutter_tools' Gradle project, specifically moving the creation of `build`
and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`.
Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle`
directories within the Nix Store. Resulting in read-only errors when trying to build a
Flutter Android app at runtime.
This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project
when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")`
`rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory.
The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it.
This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting
`rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`.
To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, we need to set `buildDirectory`.
To move `.gradle` as well, the `--project-cache-dir` argument must be passed to the Gradle wrapper.
Changing the `GradleUtils.getExecutable` function signature is a delibarate choice, to ensure that no new unpatched usages slip in.
--- /dev/null
+++ b/packages/flutter_tools/gradle/settings.gradle
@@ -0,0 +1,19 @@
+rootProject.buildFileName = "/dev/null"
+
+def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
+def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
+dir.mkdirs()
+def file = new File(dir, "settings.gradle")
+
+file.text = """
+rootProject.projectDir = new File("$settingsDir")
+apply from: new File("$settingsDir/settings.gradle.kts")
+
+gradle.allprojects { project ->
+ project.beforeEvaluate {
+ project.layout.buildDirectory = new File("$dir/build")
+ }
+}
+"""
+
+includeBuild(dir)
--- a/packages/flutter_tools/gradle/build.gradle.kts
+++ b/packages/flutter_tools/gradle/build.gradle.kts
@@ -4,6 +4,11 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+// While flutter_tools runs Gradle with a --project-cache-dir, this startParameter
+// is not passed correctly to the Kotlin Gradle plugin for some reason, and so
+// must be set here as well.
+gradle.startParameter.projectCacheDir = layout.buildDirectory.dir("cache").get().asFile
+
plugins {
`java-gradle-plugin`
groovy
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -456,9 +456,9 @@ class AndroidGradleBuilder implements AndroidBuilder {
// from the local.properties file.
updateLocalProperties(project: project, buildInfo: androidBuildInfo.buildInfo);
- final List<String> options = <String>[];
-
- final String gradleExecutablePath = _gradleUtils.getExecutable(project);
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
// All automatically created files should exist.
if (configOnly) {
@@ -781,7 +781,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
'aar_init_script.gradle',
);
final List<String> command = <String>[
- _gradleUtils.getExecutable(project),
+ ..._gradleUtils.getExecutable(project),
'-I=$initScript',
'-Pflutter-root=$flutterRoot',
'-Poutput-dir=${outputDirectory.path}',
@@ -896,6 +896,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
final List<String> results = <String>[];
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
_kBuildVariantTaskName,
preRunTask: () {
@@ -911,10 +915,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: const <String>['-q'],
+ options: <String>[...options, '-q'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
outputParser: (String line) {
if (_kBuildVariantRegex.firstMatch(line) case final RegExpMatch match) {
results.add(match.namedGroup(_kBuildVariantRegexGroupName)!);
@@ -948,6 +952,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
late Stopwatch sw;
int exitCode = 1;
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
taskName,
preRunTask: () {
@@ -963,10 +971,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: <String>['-q', '-PoutputPath=$outputPath'],
+ options: <String>[...options, '-q', '-PoutputPath=$outputPath'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
);
} on Error catch (error) {
_logger.printError(error.toString());
--- a/packages/flutter_tools/lib/src/android/gradle_errors.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart
@@ -240,7 +240,12 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
required bool usesAndroidX,
}) async {
final RunResult tasksRunResult = await globals.processUtils.run(
- <String>[globals.gradleUtils!.getExecutable(project), 'app:tasks', '--all', '--console=auto'],
+ <String>[
+ ...globals.gradleUtils!.getExecutable(project),
+ 'app:tasks',
+ '--all',
+ '--console=auto',
+ ],
throwOnError: true,
workingDirectory: project.android.hostAppGradleRoot.path,
environment: globals.java?.environment,
--- a/packages/flutter_tools/lib/src/android/gradle_utils.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:meta/meta.dart';
+import 'package:path/path.dart';
import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
@@ -154,9 +155,29 @@ class GradleUtils {
final Logger _logger;
final OperatingSystemUtils _operatingSystemUtils;
+ List<String> get _requiredArguments {
+ final String cacheDir = join(
+ switch (globals.platform.environment['XDG_CACHE_HOME']) {
+ final String cacheHome => cacheHome,
+ _ => join(
+ globals.fsUtils.homeDirPath ?? throwToolExit('No cache directory has been specified.'),
+ '.cache',
+ ),
+ },
+ 'flutter',
+ 'nix-flutter-tools-gradle',
+ globals.flutterVersion.engineRevision.substring(0, 10),
+ );
+
+ return <String>[
+ '--project-cache-dir=${join(cacheDir, 'cache')}',
+ '-Pkotlin.project.persistent.dir=${join(cacheDir, 'kotlin')}',
+ ];
+ }
+
/// Gets the Gradle executable path and prepares the Gradle project.
/// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
- String getExecutable(FlutterProject project) {
+ List<String> getExecutable(FlutterProject project) {
final Directory androidDir = project.android.hostAppGradleRoot;
injectGradleWrapperIfNeeded(androidDir);
@@ -167,7 +188,7 @@ class GradleUtils {
// If the Gradle executable doesn't have execute permission,
// then attempt to set it.
_operatingSystemUtils.makeExecutable(gradle);
- return gradle.absolute.path;
+ return <String>[gradle.absolute.path, ..._requiredArguments];
}
throwToolExit(
'Unable to locate gradlew script. Please check that ${gradle.path} '
--- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
@@ -2740,8 +2740,8 @@ Gradle Crashed
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}
--- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
@@ -1580,8 +1580,8 @@ Platform fakePlatform(String name) {
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart
index df67547..eacc7c4 100644
--- a/packages/flutter_tools/lib/src/flutter_cache.dart
+++ b/packages/flutter_tools/lib/src/flutter_cache.dart
@@ -51,16 +51,6 @@ class FlutterCache extends Cache {
registerArtifact(IosUsbArtifacts(artifactName, this, platform: platform));
}
registerArtifact(FontSubsetArtifacts(this, platform: platform));
- registerArtifact(
- PubDependencies(
- logger: logger,
- // flutter root and pub must be lazily initialized to avoid accessing
- // before the version is determined.
- flutterRoot: () => Cache.flutterRoot!,
- pub: () => pub,
- projectFactory: projectFactory,
- ),
- );
}
}

View File

@@ -0,0 +1,30 @@
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index e4e474ab6e..5548599802 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1693,7 +1693,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
- if (shouldUpdateCache) {
+ if (false) {
// First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`.
final bool offline;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index a1104da..1749d65 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -444,12 +444,8 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.analytics.suppressTelemetry();
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag =
topLevelResults[FlutterGlobalOptions.kMachineFlag] as bool? ?? false;
- if (await _shouldCheckForUpdates(topLevelResults, topLevelMachineFlag: machineFlag)) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
// See if the user specified a specific device.
final String? specifiedDeviceId =

View File

@@ -0,0 +1,68 @@
From 6df275df3b8694daf16302b407520e3b1dee6724 Mon Sep 17 00:00:00 2001
From: Philip Hayes <philiphayes9@gmail.com>
Date: Thu, 12 Sep 2024 13:23:00 -0700
Subject: [PATCH] fix: cleanup xcode_backend.sh to fix iOS build w/
`NixOS/nixpkgs` flutter
This patch cleans up `xcode_backend.sh`. It now effectively just runs
`exec $FLUTTER_ROOT/bin/dart ./xcode_backend.dart`.
The previous `xcode_backend.sh` tries to discover `$FLUTTER_ROOT` from
argv[0], even though its presence is already guaranteed (the wrapped
`xcode_backend.dart` also relies on this env).
When using nixpkgs flutter, the flutter SDK directory is composed of several
layers, joined together using symlinks (called a `symlinkJoin`). Without this
patch, the auto-discover traverses the symlinks into the wrong layer, and so it
uses an "unwrapped" `dart` command instead of a "wrapped" dart that sets some
important envs/flags (like `$FLUTTER_ROOT`).
Using the "unwrapped" dart then manifests in this error when compiling, since
it doesn't see the ios build-support artifacts:
```
$ flutter run -d iphone
Running Xcode build...
Xcode build done. 6.4s
Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.24.1-unwrapped/bin/cache/artifacts".
```
---
packages/flutter_tools/bin/xcode_backend.sh | 25 ++++-----------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 2889d7c8e4..48b9d06c6e 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -13,24 +13,7 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
-
-"$DART" "$BIN_DIR/xcode_backend.dart" "$@" "ios"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="${BASH_SOURCE[0]%.sh}.dart"
+exec "${dart}" "${xcode_backend_dart}" "$@" "ios"
--
2.46.0

View File

@@ -0,0 +1,59 @@
Fix for macOS build issue in Flutter >= 3.35
Since version 3.35, the behavior of macos_assemble.sh and xcode_backend.sh
is almost identical. This caused the same error for macOS that previously
occurred for iOS.
Derived from the iOS patch: ./fix-ios-build-xcode-backend-sh.patch
Example error:
```
$ flutter run -d macos
Launching lib/main.dart on macOS in debug mode...
Target debug_unpack_macos failed: Error: Flutter failed to create a directory at "/<nix-store>/XXXX-flutter-3.35.1-unwrapped/bin/cache/artifacts".
Please ensure that the SDK and/or project is installed in a location that has read/write permissions for the current user.
Failed to copy Flutter framework.
** BUILD FAILED **
```
---
diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh
index 28acf8842..d0f2923df 100644
--- a/packages/flutter_tools/bin/macos_assemble.sh
+++ b/packages/flutter_tools/bin/macos_assemble.sh
@@ -13,29 +13,13 @@
# exit on error, or usage of unset var
set -euo pipefail
-# Needed because if it is set, cd may print the path it changed to.
-unset CDPATH
-
-function follow_links() (
- cd -P "$(dirname -- "$1")"
- file="$PWD/$(basename -- "$1")"
- while [[ -h "$file" ]]; do
- cd -P "$(dirname -- "$file")"
- file="$(readlink -- "$file")"
- cd -P "$(dirname -- "$file")"
- file="$PWD/$(basename -- "$file")"
- done
- echo "$file"
-)
-
-PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-FLUTTER_ROOT="$BIN_DIR/../../.."
-DART="$FLUTTER_ROOT/bin/dart"
+# Run `dart ./xcode_backend.dart` with the dart from $FLUTTER_ROOT.
+dart="${FLUTTER_ROOT}/bin/dart"
+xcode_backend_dart="$(dirname "${BASH_SOURCE[0]}")/xcode_backend.dart"
# Main entry point.
if [[ $# == 0 ]]; then
- "$DART" "$BIN_DIR/xcode_backend.dart" "build" "macos"
+ exec "${dart}" "${xcode_backend_dart}" "build" "macos"
else
- "$DART" "$BIN_DIR/xcode_backend.dart" "$@" "macos"
+ exec "${dart}" "${xcode_backend_dart}" "$@" "macos"
fi

View File

@@ -0,0 +1,220 @@
This patch introduces an intermediate Gradle build step to alter the behavior
of flutter_tools' Gradle project, specifically moving the creation of `build`
and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`.
Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle`
directories within the Nix Store. Resulting in read-only errors when trying to build a
Flutter Android app at runtime.
This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project
when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")`
`rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory.
The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it.
This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting
`rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`.
To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, we need to set `buildDirectory`.
To move `.gradle` as well, the `--project-cache-dir` argument must be passed to the Gradle wrapper.
Changing the `GradleUtils.getExecutable` function signature is a delibarate choice, to ensure that no new unpatched usages slip in.
--- /dev/null
+++ b/packages/flutter_tools/gradle/settings.gradle
@@ -0,0 +1,19 @@
+rootProject.buildFileName = "/dev/null"
+
+def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
+def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
+dir.mkdirs()
+def file = new File(dir, "settings.gradle")
+
+file.text = """
+rootProject.projectDir = new File("$settingsDir")
+apply from: new File("$settingsDir/settings.gradle.kts")
+
+gradle.allprojects { project ->
+ project.beforeEvaluate {
+ project.layout.buildDirectory = new File("$dir/build")
+ }
+}
+"""
+
+includeBuild(dir)
--- a/packages/flutter_tools/gradle/build.gradle.kts
+++ b/packages/flutter_tools/gradle/build.gradle.kts
@@ -4,6 +4,11 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+// While flutter_tools runs Gradle with a --project-cache-dir, this startParameter
+// is not passed correctly to the Kotlin Gradle plugin for some reason, and so
+// must be set here as well.
+gradle.startParameter.projectCacheDir = layout.buildDirectory.dir("cache").get().asFile
+
plugins {
`java-gradle-plugin`
groovy
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -474,9 +474,9 @@ class AndroidGradleBuilder implements AndroidBuilder {
// from the local.properties file.
updateLocalProperties(project: project, buildInfo: androidBuildInfo.buildInfo);
- final options = <String>[];
-
- final String gradleExecutablePath = _gradleUtils.getExecutable(project);
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
// All automatically created files should exist.
if (configOnly) {
@@ -797,7 +797,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
'aar_init_script.gradle',
);
final command = <String>[
- _gradleUtils.getExecutable(project),
+ ..._gradleUtils.getExecutable(project),
'-I=$initScript',
'-Pflutter-root=$flutterRoot',
'-Poutput-dir=${outputDirectory.path}',
@@ -912,6 +912,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
final results = <String>[];
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
_kBuildVariantTaskName,
preRunTask: () {
@@ -927,10 +931,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: const <String>['-q'],
+ options: <String>[...options, '-q'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
outputParser: (String line) {
if (_kBuildVariantRegex.firstMatch(line) case final RegExpMatch match) {
results.add(match.namedGroup(_kBuildVariantRegexGroupName)!);
@@ -964,6 +968,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
late Stopwatch sw;
var exitCode = 1;
try {
+ final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable(
+ project,
+ );
+
exitCode = await _runGradleTask(
taskName,
preRunTask: () {
@@ -979,10 +987,10 @@ class AndroidGradleBuilder implements AndroidBuilder {
),
);
},
- options: <String>['-q', '-PoutputPath=$outputPath'],
+ options: <String>[...options, '-q', '-PoutputPath=$outputPath'],
project: project,
localGradleErrors: gradleErrors,
- gradleExecutablePath: _gradleUtils.getExecutable(project),
+ gradleExecutablePath: gradleExecutablePath,
);
} on Error catch (error) {
_logger.printError(error.toString());
--- a/packages/flutter_tools/lib/src/android/gradle_errors.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart
@@ -228,7 +228,12 @@ final flavorUndefinedHandler = GradleHandledError(
},
handler: ({required String line, required FlutterProject project, required bool usesAndroidX}) async {
final RunResult tasksRunResult = await globals.processUtils.run(
- <String>[globals.gradleUtils!.getExecutable(project), 'app:tasks', '--all', '--console=auto'],
+ <String>[
+ ...globals.gradleUtils!.getExecutable(project),
+ 'app:tasks',
+ '--all',
+ '--console=auto',
+ ],
throwOnError: true,
workingDirectory: project.android.hostAppGradleRoot.path,
environment: globals.java?.environment,
--- a/packages/flutter_tools/lib/src/android/gradle_utils.dart
+++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:meta/meta.dart';
+import 'package:path/path.dart';
import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
@@ -197,9 +198,29 @@ class GradleUtils {
final Logger _logger;
final OperatingSystemUtils _operatingSystemUtils;
+ List<String> get _requiredArguments {
+ final String cacheDir = join(
+ switch (globals.platform.environment['XDG_CACHE_HOME']) {
+ final String cacheHome => cacheHome,
+ _ => join(
+ globals.fsUtils.homeDirPath ?? throwToolExit('No cache directory has been specified.'),
+ '.cache',
+ ),
+ },
+ 'flutter',
+ 'nix-flutter-tools-gradle',
+ globals.flutterVersion.engineRevision.substring(0, 10),
+ );
+
+ return <String>[
+ '--project-cache-dir=${join(cacheDir, 'cache')}',
+ '-Pkotlin.project.persistent.dir=${join(cacheDir, 'kotlin')}',
+ ];
+ }
+
/// Gets the Gradle executable path and prepares the Gradle project.
/// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
- String getExecutable(FlutterProject project) {
+ List<String> getExecutable(FlutterProject project) {
final Directory androidDir = project.android.hostAppGradleRoot;
injectGradleWrapperIfNeeded(androidDir);
@@ -210,7 +231,7 @@ class GradleUtils {
// If the Gradle executable doesn't have execute permission,
// then attempt to set it.
_operatingSystemUtils.makeExecutable(gradle);
- return gradle.absolute.path;
+ return <String>[gradle.absolute.path, ..._requiredArguments];
}
throwToolExit(
'Unable to locate gradlew script. Please check that ${gradle.path} '
--- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
@@ -2606,8 +2606,8 @@ Gradle Crashed
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}
--- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
@@ -1633,8 +1633,8 @@ Platform fakePlatform(String name) {
class FakeGradleUtils extends Fake implements GradleUtils {
@override
- String getExecutable(FlutterProject project) {
- return 'gradlew';
+ List<String> getExecutable(FlutterProject project) {
+ return const <String>['gradlew'];
}
}

View File

@@ -0,0 +1,211 @@
{
lib,
stdenv,
darwin,
callPackage,
flutter,
supportedTargetFlutterPlatforms ? [
"universal"
"web"
]
++ lib.optional (stdenv.hostPlatform.isLinux && !(flutter ? engine)) "linux"
++ lib.optional (stdenv.hostPlatform.isx86_64 || stdenv.hostPlatform.isDarwin) "android"
++ lib.optionals stdenv.hostPlatform.isDarwin [
"macos"
"ios"
],
artifactHashes ? flutter.artifactHashes,
extraPkgConfigPackages ? [ ],
extraLibraries ? [ ],
extraIncludes ? [ ],
extraCxxFlags ? [ ],
extraCFlags ? [ ],
extraLinkerFlags ? [ ],
makeWrapper,
writeShellScript,
wrapGAppsHook3,
git,
which,
pkg-config,
atk,
cairo,
gdk-pixbuf,
glib,
gtk3,
harfbuzz,
libepoxy,
pango,
libX11,
xorgproto,
libdeflate,
zlib,
cmake,
ninja,
clang,
symlinkJoin,
}:
let
supportsLinuxDesktopTarget = builtins.elem "linux" supportedTargetFlutterPlatforms;
flutterPlatformArtifacts = lib.genAttrs supportedTargetFlutterPlatforms (
flutterPlatform:
(callPackage ./artifacts/prepare-artifacts.nix {
src = callPackage ./artifacts/fetch-artifacts.nix {
inherit flutterPlatform;
systemPlatform = stdenv.hostPlatform.system;
flutter = callPackage ./wrapper.nix { inherit flutter; };
hash = artifactHashes.${flutterPlatform}.${stdenv.hostPlatform.system} or "";
};
})
);
cacheDir = symlinkJoin {
name = "flutter-cache-dir";
paths = builtins.attrValues flutterPlatformArtifacts;
postBuild = ''
mkdir -p "$out/bin/cache"
ln -s '${flutter}/bin/cache/dart-sdk' "$out/bin/cache"
'';
passthru.flutterPlatform = flutterPlatformArtifacts;
};
# By default, Flutter stores downloaded files (such as the Pub cache) in the SDK directory.
# Wrap it to ensure that it does not do that, preferring home directories instead.
immutableFlutter = writeShellScript "flutter_immutable" ''
export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
${flutter}/bin/flutter "$@"
'';
# Tools that the Flutter tool depends on.
tools = [
git
which
];
# Libraries that Flutter apps depend on at runtime.
appRuntimeDeps = lib.optionals supportsLinuxDesktopTarget [
atk
cairo
gdk-pixbuf
glib
gtk3
harfbuzz
libepoxy
pango
libX11
libdeflate
];
# Development packages required for compilation.
appBuildDeps =
let
# https://discourse.nixos.org/t/handling-transitive-c-dependencies/5942/3
deps =
pkg: lib.filter lib.isDerivation ((pkg.buildInputs or [ ]) ++ (pkg.propagatedBuildInputs or [ ]));
withKey = pkg: {
key = pkg.outPath;
val = pkg;
};
collect = pkg: lib.map withKey ([ pkg ] ++ deps pkg);
in
lib.map (e: e.val) (
lib.genericClosure {
startSet = lib.map withKey appRuntimeDeps;
operator = item: collect item.val;
}
);
# Some header files and libraries are not properly located by the Flutter SDK.
# They must be manually included.
appStaticBuildDeps =
(lib.optionals supportsLinuxDesktopTarget [
libX11
xorgproto
zlib
])
++ extraLibraries;
# Tools used by the Flutter SDK to compile applications.
buildTools = lib.optionals supportsLinuxDesktopTarget [
pkg-config
cmake
ninja
clang
];
# Nix-specific compiler configuration.
pkgConfigPackages = map (lib.getOutput "dev") (appBuildDeps ++ extraPkgConfigPackages);
includeFlags = map (pkg: "-isystem ${lib.getOutput "dev" pkg}/include") (
appStaticBuildDeps ++ extraIncludes
);
linkerFlags =
(map (pkg: "-rpath,${lib.getOutput "lib" pkg}/lib") appRuntimeDeps) ++ extraLinkerFlags;
in
(callPackage ./sdk-symlink.nix { }) (
stdenv.mkDerivation {
pname = "flutter-wrapped";
inherit (flutter) version;
nativeBuildInputs = [
makeWrapper
]
++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.DarwinTools ]
++ lib.optionals supportsLinuxDesktopTarget [
glib
wrapGAppsHook3
];
passthru = flutter.passthru // {
inherit (flutter) version;
unwrapped = flutter;
updateScript = ./update/update.py;
inherit cacheDir;
};
dontUnpack = true;
dontWrapGApps = true;
installPhase = ''
runHook preInstall
for path in ${
builtins.concatStringsSep " " (
builtins.foldl' (
paths: pkg:
paths
++ (map (directory: "'${pkg}/${directory}/pkgconfig'") [
"lib"
"share"
])
) [ ] pkgConfigPackages
)
}; do
addToSearchPath FLUTTER_PKG_CONFIG_PATH "$path"
done
mkdir -p $out/bin
makeWrapper '${immutableFlutter}' $out/bin/flutter \
--set-default ANDROID_EMULATOR_USE_SYSTEM_LIBS 1 \
''
+ lib.optionalString (flutter ? engine && flutter.engine.meta.available) ''
--set-default FLUTTER_ENGINE "${flutter.engine}" \
--add-flags "--local-engine-host ${flutter.engine.outName}" \
''
+ ''
--suffix PATH : '${lib.makeBinPath (tools ++ buildTools)}' \
--suffix PKG_CONFIG_PATH : "$FLUTTER_PKG_CONFIG_PATH" \
--suffix LIBRARY_PATH : '${lib.makeLibraryPath appStaticBuildDeps}' \
--prefix CXXFLAGS "''\t" '${builtins.concatStringsSep " " (includeFlags ++ extraCxxFlags)}' \
--prefix CFLAGS "''\t" '${builtins.concatStringsSep " " (includeFlags ++ extraCFlags)}' \
--prefix LDFLAGS "''\t" '${
builtins.concatStringsSep " " (map (flag: "-Wl,${flag}") linkerFlags)
}' \
''${gappsWrapperArgs[@]}
runHook postInstall
'';
inherit (flutter) meta;
}
)