Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{ lib
, fetchFromGitLab
, flutter
, olm
}:

flutter.mkFlutterApp rec {
pname = "fluffychat";
version = "1.2.0";

vendorHash = "sha256-Qg0IlajbIl8e3BkKgn4O+mbZGvhfqr7XwllBLJQAA/I=";

src = fetchFromGitLab {
owner = "famedly";
repo = "fluffychat";
rev = "v${version}";
hash = "sha256-PJH3jMQc6u9R6Snn+9rNN8t+8kt6l3Xt7zKPbpqj13E=";
};

buildInputs = [
olm
];

meta = with lib; {
description = "Chat with your friends (matrix client)";
homepage = "https://fluffychat.im/";
license = licenses.agpl3Plus;
maintainers = with maintainers; [ mkg20001 ];
platforms = platforms.linux;
};
}
45 changes: 45 additions & 0 deletions pkgs/build-support/fetchgit/deterministic-git
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/sh

# some git commands print to stdout, which would contaminate our JSON output
clean_git(){
git "$@" >&2
}

# Remove all remote branches, remove tags not reachable from HEAD, do a full
# repack and then garbage collect unreferenced objects.
make_deterministic_repo(){
local repo="$1"

# run in sub-shell to not touch current working directory
(
cd "$repo"
# Remove files that contain timestamps or otherwise have non-deterministic
# properties.
rm -rf .git/logs/ .git/hooks/ .git/index .git/FETCH_HEAD .git/ORIG_HEAD \
.git/refs/remotes/origin/HEAD .git/config

# Remove all remote branches.
git branch -r | while read -r branch; do
clean_git branch -rD "$branch"
done

# Remove tags not reachable from HEAD. If we're exactly on a tag, don't
# delete it.
maybe_tag=$(git tag --points-at HEAD)
git tag --contains HEAD | while read -r tag; do
if [ "$tag" != "$maybe_tag" ]; then
clean_git tag -d "$tag"
fi
done

# Do a full repack. Must run single-threaded, or else we lose determinism.
clean_git config pack.threads 1
clean_git repack -A -d -f
rm -f .git/config

# Garbage collect unreferenced objects.
# Note: --keep-largest-pack prevents non-deterministic ordering of packs
# listed in .git/objects/info/packs by only using a single pack
clean_git gc --prune=all --keep-largest-pack
)
}
277 changes: 277 additions & 0 deletions pkgs/build-support/flutter/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
{ flutter
, lib
, llvmPackages_13
, cmake
, ninja
, pkg-config
, wrapGAppsHook
, autoPatchelfHook
, util-linux
, libselinux
, libsepol
, libthai
, libdatrie
, libxkbcommon
, at-spi2-core
, libsecret
, jsoncpp
, xorg
, dbus
, gtk3
, glib
, pcre
, libepoxy
, stdenvNoCC
, cacert
, git
, dart
, nukeReferences
, targetPlatform
, bash
, curl
, unzip
, which
, xz
}:

# absolutely no mac support for now

args:
let
pl = n: "##FLUTTER_${n}_PLACEHOLDER_MARKER##";
placeholder_deps = pl "DEPS";
placeholder_flutter = pl "FLUTTER";
fetchAttrs = [ "src" "sourceRoot" "setSourceRoot" "unpackPhase" "patches" ];
getAttrsOrNull = names: attrs: lib.genAttrs names (name: if attrs ? ${name} then attrs.${name} else null);
flutterDeps = [
# flutter deps
flutter.unwrapped
bash
curl
flutter.dart
git
unzip
which
xz
];
self =
(self: llvmPackages_13.stdenv.mkDerivation (args // {
deps = stdenvNoCC.mkDerivation (lib.recursiveUpdate (getAttrsOrNull fetchAttrs args) {
name = "${self.name}-deps-flutter-v${flutter.unwrapped.version}-${targetPlatform.system}.tar.gz";

nativeBuildInputs = flutterDeps ++ [
nukeReferences
];

installPhase = ''
. ${../fetchgit/deterministic-git}

TMP=$(mktemp -d)

export HOME="$TMP"
export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1

flutter config --no-analytics &>/dev/null # mute first-run
flutter config --enable-linux-desktop
flutter packages get
flutter build linux || true # so it downloads tools

RES="$TMP"

mkdir -p "$RES/f"

# so we can use lock, diff yaml
cp "pubspec.yaml" "$RES"
cp "pubspec.lock" "$RES"
mv .dart_tool .flutter-plugins .flutter-plugins-dependencies .packages "$RES/f"

# replace paths with placeholders
find "$RES" -type f -exec sed -i \
-e s,$TMP,${placeholder_deps},g \
-e s,${flutter.unwrapped},${placeholder_flutter},g \
{} +

remove_line_matching() {
replace_line_matching "$1" "$2" ""
}

replace_line_matching() {
sed "s|.*$2.*|$3|g" -r -i "$1"
}

# nuke nondeterminism

# clientId is random
remove_line_matching "$RES/.flutter" clientId

# deterministic git repos
find "$RES" -iname .git -type d | while read -r repoGit; do
make_deterministic_repo "$(dirname "$repoGit")"
done

# dart _fetchedAt, etc
DART_DATE=$(date --date="@$SOURCE_DATE_EPOCH" -In | sed "s|,|.|g" | sed "s|+.*||g")
find "$RES/.pub-cache" -iname "*.json" -exec sed -r 's|.*_fetchedAt.*| "_fetchedAt": "'"$DART_DATE"'",|g' -i {} +
replace_line_matching "$RES/f/.dart_tool/package_config.json" '"generated"' '"generated": "'"$DART_DATE"'",'
replace_line_matching "$RES/f/.flutter-plugins-dependencies" '"date_created"' '"date_created": "'"$DART_DATE"'",'
remove_line_matching "$RES/f/.packages" "Generated by pub"

# nuke refs
find "$RES" -type f -exec nuke-refs {} +

# Build a reproducible tar, per instructions at https://reproducible-builds.org/docs/archives/
tar --owner=0 --group=0 --numeric-owner --format=gnu \
--sort=name --mtime="@$SOURCE_DATE_EPOCH" \
-czf "$out" -C "$RES" .
'';

GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";

impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
"GIT_PROXY_COMMAND" "NIX_GIT_SSL_CAINFO" "SOCKS_SERVER"
];

# unnecesarry
dontFixup = true;

outputHashAlgo = if self ? vendorHash then null else "sha256";
# outputHashMode = "recursive";
outputHash = if self ? vendorHash then
self.vendorHash
else if self ? vendorSha256 then
self.vendorSha256
else
lib.fakeSha256;

});

nativeBuildInputs = flutterDeps ++ [
# flutter dev tools
cmake
ninja
pkg-config
wrapGAppsHook
# flutter likes dynamic linking
autoPatchelfHook
] ++ lib.optionals (args ? nativeBuildInputs) args.nativeBuildInputs;

buildInputs = [
# cmake deps
gtk3
glib
pcre
util-linux
# also required by cmake, not sure if really needed or dep of all packages
libselinux
libsepol
libthai
libdatrie
xorg.libXdmcp
xorg.libXtst
libxkbcommon
dbus
at-spi2-core
libsecret
jsoncpp
# build deps
xorg.libX11
# directly required by build
libepoxy
] ++ lib.optionals (args ? buildInputs) args.buildInputs;

# TODO: do we need this?
NIX_LDFLAGS = "-rpath ${lib.makeLibraryPath self.buildInputs}";
NIX_CFLAGS_COMPILE = "-I${xorg.libX11}/include";
LD_LIBRARY_PATH = lib.makeLibraryPath self.buildInputs;

configurePhase = ''
runHook preConfigure

# for some reason fluffychat build breaks without this - seems file gets overriden by some tool
cp pubspec.yaml pubspec-backup

# we get this from $depsFolder so disabled for now, but we might need it again once deps are fetched properly
# flutter config --no-analytics >/dev/null 2>/dev/null # mute first-run
# flutter config --enable-linux-desktop

# extract deps
depsFolder=$(mktemp -d)
tar xzf "$deps" -C "$depsFolder"

# after extracting update paths to point to real paths
find "$depsFolder" -type f -exec sed -i \
-e s,${placeholder_deps},$depsFolder,g \
-e s,${placeholder_flutter},${flutter.unwrapped},g \
{} +

# ensure we're using a lockfile for the right package version
if [ -e pubspec.lock ]; then
# diff -u pubspec.lock $depsFolder/pubspec.lock
true
else
cp -v "$depsFolder/pubspec.lock" .
fi
diff -u pubspec.yaml $depsFolder/pubspec.yaml

mv -v $(find $depsFolder/f -type f) .

# prepare
export HOME=$depsFolder
export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1

# binaries need to be patched
autoPatchelf -- "$depsFolder"

runHook postConfigure
'';

buildPhase = ''
runHook preBuild

# for some reason fluffychat build breaks without this - seems file gets overriden by some tool
mv pubspec-backup pubspec.yaml
mkdir -p build/flutter_assets/fonts

flutter packages get --offline -v
flutter build linux --release -v

runHook postBuild
'';

installPhase = ''
runHook preInstall

built=build/linux/*/release/bundle

mkdir -p $out/bin
mv $built $out/app

for f in $built/data/flutter_assets/assets/*.desktop; do
install -D $f $out/share/applications/$(basename $f)
done
for f in $(find $out/app -maxdepth 1 -type f); do
ln -s $f $out/bin/$(basename $f)
done

# this confuses autopatchelf hook otherwise
rm -rf "$depsFolder"

# make *.so executable
find $out/app -iname "*.so" -type f -exec chmod +x {} +

# remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral
for f in $(find $out/app -executable -type f); do
if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also
echo "strip RPath of $f"
newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g")
patchelf --set-rpath "$newrp" "$f"
fi
done

runHook postInstall
'';
})) self;
in
self
10 changes: 9 additions & 1 deletion pkgs/development/compilers/flutter/flutter.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
, nss
, systemd
, which
, callPackage
}:
let
drvName = "flutter-${version}";
Expand Down Expand Up @@ -146,6 +147,8 @@ let
};

in
let
self = (self:
runCommand drvName
{
startScript = ''
Expand All @@ -159,6 +162,9 @@ runCommand drvName
passthru = {
unwrapped = flutter;
inherit dart;
mkFlutterApp = callPackage ../../../build-support/flutter {
flutter = self;
};
};
meta = with lib; {
description = "Flutter is Google's SDK for building mobile, web and desktop with Dart";
Expand All @@ -179,4 +185,6 @@ runCommand drvName

echo -n "$startScript" > $out/bin/${pname}
chmod +x $out/bin/${pname}
''
'') self;
in
self
Loading