diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..96bf5daae1 --- /dev/null +++ b/.envrc @@ -0,0 +1,11 @@ +# shellcheck shell=bash +# vim: ft=bash +if ! has nix_direnv_version || ! nix_direnv_version 3.1.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.1/direnvrc" "sha256-p+fzQdrms/hDa7g+soShAybJNo4bN4SIAeSfqNKgD5I=" +fi + +export DIRENV_WARN_TIMEOUT=20s +export NIX_CONFIG="include ${PWD}/nix/nix.conf" + +watch_dir nix +use flake diff --git a/.gitignore b/.gitignore index 6615a33a93..c113ca1aae 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ mobile/android/qt6/.gradle/ # Used to track the simulated keycard mode changes via the USE_SIMULATED_KEYCARD build flag .use_simulated_keycard_previous *.qm +.direnv/ # Squish test ================================================================ diff --git a/Makefile b/Makefile index 1584f0a43f..3aa40081d4 100644 --- a/Makefile +++ b/Makefile @@ -83,10 +83,6 @@ else # "variables.mk" was included. Business as usual until the end of this file all: nim_status_client -nix-shell: export NIX_USER_CONF_FILES := $(PWD)/nix/nix.conf -nix-shell: - nix-shell - # must be included after the default target -include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk @@ -97,17 +93,17 @@ ifneq ($(QMAKE),$(shell which qmake)) # Add it to PATH for external build tools that use qmake directly export PATH := $(patsubst %/,%,$(dir $(QMAKE))):$(PATH) endif -QSPEC:=$(shell $(QMAKE) -query QMAKE_XSPEC) +QSPEC := $(shell $(QMAKE) -query QMAKE_XSPEC) ifeq ($(QSPEC),macx-ios-clang) -mkspecs:=ios +mkspecs := ios else ifeq ($(QSPEC),macx-clang) -mkspecs:=macx +mkspecs := macx else ifeq ($(QSPEC),win32-msvc) -mkspecs:=win32 +mkspecs := win32 else ifeq ($(QSPEC),linux-g++) -mkspecs:=linux +mkspecs := linux else ifeq ($(QSPEC),android-clang) -mkspecs:=android +mkspecs := android endif host_os:=$(shell uname -s | tr '[:upper:]' '[:lower:]') @@ -159,6 +155,15 @@ else RUN_TARGET := run-linux endif +NIXOS := $(shell test -e /etc/NIXOS && echo 1) +ifeq ($(host_os),linux) + ifndef NIXOS + ifdef IN_NIX_SHELL + NIXGL_WRAPPER ?= nixGLIntel + endif + endif +endif + check-qt-dir: ifeq ($(shell $(QMAKE) -v 2>/dev/null),) $(error Cannot find your Qt installation. Please make sure to export correct Qt installation binaries path to PATH env) @@ -440,7 +445,7 @@ statusq-tests: run-statusq-tests: export QTWEBENGINE_CHROMIUM_FLAGS := "${QTWEBENGINE_CHROMIUM_FLAGS} --disable-seccomp-filter-sandbox" run-statusq-tests: statusq-tests echo -e "\033[92mRunning:\033[39m StatusQ Unit Tests" - ctest -V --test-dir $(STATUSQ_BUILD_PATH) ${ARGS} + $(NIXGL_WRAPPER) ctest -V --test-dir $(STATUSQ_BUILD_PATH) ${ARGS} ## ## Storybook @@ -477,11 +482,11 @@ storybook-build: | storybook-configure run-storybook: storybook-build echo -e "\033[92mRunning:\033[39m Storybook" - $(STORYBOOK_BINARY) ${ARGS} + $(NIXGL_WRAPPER) $(STORYBOOK_BINARY) ${ARGS} run-storybook-tests: storybook-build echo -e "\033[92mRunning:\033[39m Storybook Tests" - ctest -V --test-dir $(STORYBOOK_BUILD_PATH) -E PagesValidator + $(NIXGL_WRAPPER) ctest -V --test-dir $(STORYBOOK_BUILD_PATH) -E PagesValidator # repeat because of https://bugreports.qt.io/browse/QTBUG-92236 (Qt < 5.15.4) run-storybook-pages-validator: storybook-build @@ -913,13 +918,17 @@ MACOS_INNER_BUNDLE := $(MACOS_OUTER_BUNDLE)/Contents/Frameworks/QtWebEngineCore. STATUS_CLIENT_DMG ?= pkg/Status.dmg +$(STATUS_CLIENT_DMG): MACOS_OUTER_BUNDLE := tmp/macos/dist/Status.app +$(STATUS_CLIENT_DMG): MACOS_INNER_BUNDLE := $(MACOS_OUTER_BUNDLE)/Contents/Frameworks/QtWebEngineCore.framework/Versions/Current/Helpers/QtWebEngineProcess.app $(STATUS_CLIENT_DMG): override RESOURCES_LAYOUT := $(PRODUCTION_PARAMETERS) $(STATUS_CLIENT_DMG): ENTITLEMENTS ?= resources/Entitlements.plist $(STATUS_CLIENT_DMG): nim_status_client rm -rf tmp/macos pkg/*.dmg - mkdir -p $(MACOS_OUTER_BUNDLE)/Contents/MacOS - mkdir -p $(MACOS_OUTER_BUNDLE)/Contents/Resources - cp Info.plist $(MACOS_OUTER_BUNDLE)/Contents/ + mkdir -p \ + $(MACOS_OUTER_BUNDLE)/Contents/Resources \ + $(MACOS_OUTER_BUNDLE)/Contents/MacOS + cp -R Info.plist status-macos.svg resources.rcc \ + $(MACOS_OUTER_BUNDLE)/Contents/ cp bin/nim_status_client $(MACOS_OUTER_BUNDLE)/Contents/MacOS/ cp status.icns $(MACOS_OUTER_BUNDLE)/Contents/Resources/ cp resources/macos/Assets.car $(MACOS_OUTER_BUNDLE)/Contents/Resources/ @@ -932,12 +941,11 @@ ifeq ($(USE_SIMULATED_KEYCARD),true) endif echo -e $(BUILD_MSG) "app" - MAC_QTQMLDIR=$(shell $(QMAKE) -query QT_INSTALL_QML) && \ macdeployqt \ $(MACOS_OUTER_BUNDLE) \ -executable=$(MACOS_OUTER_BUNDLE)/Contents/MacOS/nim_status_client \ -qmldir=ui \ - -qmlimport=$$MAC_QTQMLDIR \ + -qmlimport=$(QT_QMLDIR) macdeployqt \ $(MACOS_INNER_BUNDLE) \ -executable=$(MACOS_INNER_BUNDLE)/Contents/MacOS/QtWebEngineProcess @@ -948,10 +956,11 @@ ifdef MACOS_CODESIGN_IDENT scripts/sign-macos-pkg.sh $(MACOS_OUTER_BUNDLE) $(MACOS_CODESIGN_IDENT) \ --entitlements $(ENTITLEMENTS) endif + echo -e $(BUILD_MSG) "dmg" mkdir -p pkg - nix shell .#dmgbuild \ - -c dmgbuild -s scripts/dmg-settings.py -D app=$(MACOS_OUTER_BUNDLE) "Status" pkg/Status.dmg + nix run .#dmgbuild -- \ + -s scripts/dmg-settings.py -D app=$(MACOS_OUTER_BUNDLE) "Status" pkg/Status.dmg mv "`ls pkg/*.dmg`" $(STATUS_CLIENT_DMG) ifdef MACOS_CODESIGN_IDENT @@ -1056,10 +1065,11 @@ run: $(RUN_TARGET) # STATUS_PORT ?= 30306 # WAKUV2_PORT ?= 30307 + run-linux: nim_status_client echo -e "\033[92mRunning:\033[39m bin/nim_status_client" LD_LIBRARY_PATH="$(QT_LIBDIR)":"$(NIMSDS_LIBDIR)":"$(STATUSGO_LIBDIR)":"$(STATUSKEYCARD_QT_LIBDIR)":"$(STATUSQ_LIB_PATH)":"$(EXTRA_LIBS_PATH)":"$(LD_LIBRARY_PATH)" \ - ./bin/nim_status_client $(ARGS) + $(NIXGL_WRAPPER) ./bin/nim_status_client $(ARGS) run-linux-gdb: nim_status_client echo -e "\033[92mRunning:\033[39m bin/nim_status_client" diff --git a/flake.lock b/flake.lock index f732214418..92afbc02a4 100644 --- a/flake.lock +++ b/flake.lock @@ -1,24 +1,96 @@ { "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762090880, + "narHash": "sha256-fbRQzIGPkjZa83MowjbD2ALaJf9y6KMDdJBQMKFeY/8=", + "owner": "nix-community", + "repo": "nixGL", + "rev": "b6105297e6f0cd041670c3e8628394d4ee247ed5", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixGL", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1770770419, - "narHash": "sha256-iKZMkr6Cm9JzWlRYW/VPoL0A9jVKtZYiU4zSrVeetIs=", + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6c5e707c6b5339359a9a9e215c5e66d6d802fd7a", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-25.11", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1779560665, + "narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "nixpkgs": "nixpkgs" + "nixgl": "nixgl", + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 689e5a6f80..dc8212a2dc 100644 --- a/flake.nix +++ b/flake.nix @@ -1,29 +1,65 @@ { - description = "Status Desktop build tools"; + description = "status-app"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + # NOTE: 25.11 has a newer Qt and some tool (which?) version failing + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; + + nixgl = { + inputs.nixpkgs.follows = "nixpkgs"; + url = "github:nix-community/nixGL"; + }; }; - outputs = { self, nixpkgs }: - let - systems = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ]; - forAllSystems = f: nixpkgs.lib.genAttrs systems f; - in { - packages = forAllSystems (system: - let pkgs = nixpkgs.legacyPackages.${system}; - in { - jdk = pkgs.jdk; # keycard simulator precompile (USE_SIMULATED_KEYCARD packages) - } // nixpkgs.lib.optionalAttrs pkgs.stdenv.isDarwin { - dmgbuild = pkgs.python3Packages.dmgbuild.overrideAttrs (old: rec { - version = "1.6.7"; - src = pkgs.fetchPypi { - pname = "dmgbuild"; - inherit version; - hash = "sha256-Z2sXrNRIiZ9tSoOyGE4GV0gEROy2rJxJIoie+tnl2/s="; - }; - }); + outputs = { + self, + nixpkgs, + nixpkgs-unstable, + nixgl, + }: let + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + + forAllSystems = nixpkgs.lib.genAttrs systems; + + pkgsFor = forAllSystems ( + system: + import nixpkgs { + inherit system; + overlays = [ + nixgl.overlay + self.overlays.default + (final: prev: { + unstablePkgs = import nixpkgs-unstable { + inherit (prev) system; + }; + }) + ]; } - ); - }; + ); + in { + overlays.default = import ./nix/overlays.nix; + + devShells = forAllSystems (system: { + default = pkgsFor.${system}.callPackage ./nix/devshell.nix {}; + }); + + packages = forAllSystems ( + system: let + pkgs = pkgsFor.${system}; + in + { + inherit (pkgs) jdk; # keycard simulator precompile (USE_SIMULATED_KEYCARD packages) + } + // nixpkgs.lib.optionalAttrs pkgs.stdenv.isDarwin { + inherit (pkgs) fileicon; + inherit (pkgs.unstablePkgs.python313Packages) dmgbuild; + } + ); + }; } diff --git a/nix/README.md b/nix/README.md new file mode 100644 index 0000000000..8f8f10dff9 --- /dev/null +++ b/nix/README.md @@ -0,0 +1,37 @@ +# Description + +This folder contains configuration for [Nix](https://nixos.org/), a purely functional package manager used by the Status Go for its build process. + +## Prerequisites + +Install Nix: + +```sh +sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon +``` + +Install direnv: + +```sh +brew install direnv # macOS +sudo apt install direnv # Ubuntu +sudo dnf install direnv # Fedora +``` + +## Configuration + +The main config file is [`nix/nix.conf`](/nix/nix.conf) and its main purpose is defining the [binary caches](https://nixos.org/nix/manual/#ch-basic-package-mgmt) which allow download of packages to avoid having to compile them yourself locally. + +## Shell + +In order to access an interactive Nix shell a user should run `nix develop`. + +But better way is to use `direnv allow`. So it will run a nix shell every time you enter the workdir. +It will also reload the shell in case of nix configuration changes. + +## Resources + +You can learn more about Nix by watching these presentations: + +* [Nix Fundamentals](https://www.youtube.com/watch?v=m4sv2M9jRLg) ([PDF](https://drive.google.com/file/d/1Tt5R7QOubudGiSuZIGxuFWB1OYgcThcL/view?usp=sharing), [src](https://github.com/status-im/infra-docs/tree/master/presentations/nix_basics)) +* [Nix in Status](https://www.youtube.com/watch?v=rEQ1EvRG8Wc) ([PDF](https://drive.google.com/file/d/1Ti0wppMoj40icCPdHy7mJcQj__DeaYBE/view?usp=sharing), [src](https://github.com/status-im/infra-docs/tree/master/presentations/nix_in_status)) diff --git a/nix/devshell.nix b/nix/devshell.nix new file mode 100644 index 0000000000..0d9e787ae9 --- /dev/null +++ b/nix/devshell.nix @@ -0,0 +1,89 @@ +{pkgs}: let + # NOTE: llvm19+ has an issue with zxing-cpp + llvm18 = pkgs.llvmPackages_18; + mkShell18 = pkgs.mkShell.override {stdenv = llvm18.libcxxStdenv;}; + mkShell = + if pkgs.stdenv.isDarwin + then mkShell18 + else pkgs.mkShell; + qt6-env = with pkgs.qt6; + env "qt6-env" [ + qtbase + qtdeclarative + qtmultimedia + qtsvg + qttools + qtwebchannel + qtwebengine + qtwebview + # runtime + qt5compat + qtscxml + # storybook + qthttpserver + qtwebsockets + # statusq-tests + qtpositioning + ]; +in + mkShell { + packages = with pkgs; + [ + cmake # 3.31.6 + gcc # for nim compilation + git + go-bindata + go_1_24 # 1.24.10 + libglvnd + mockgen # v0.5.2 + nim # 2.2.4 + openssl + pcre + pkg-config + protobuf_21 + protoc-gen-go # v1.36.6 + qt6-env # 6.9.3 + which + ] + ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ + # TODO: + # - apple-sdk version + unstablePkgs.python313Packages.dmgbuild + fileicon + ]) + ++ pkgs.lib.optionals pkgs.stdenv.isLinux (with pkgs; [ + # Darwin requires system pcsclite for keycard-go + pcsclite + # nixGLIntel works in pure shell + # auto.nixGLDefault requires impure shell + nixgl.nixGLIntel + ]); + + shellHook = '' + case "$OSTYPE" in + darwin*) + # nix stdenv adds find incompatible with macos build + export PATH="/usr/bin:$PATH" + ;; + esac + + # Sanitizing env vars enforcing Go to use Nix provided toolchain + # GOPATH, GOCACHE, GOMODCACHE will be used from user home + unset GOROOT + export GOENV=off + export GOTOOLCHAIN=local + ''; + + # NOTE: LD_LIBRARY_PATH is a last resort tool + # Prefer binary RPATH, which is easy to fix with mkDerivation + LD_LIBRARY_PATH = with pkgs; + lib.makeLibraryPath [ + # NOTE: RPATH is missing it + openssl + ]; + + # NOTE: smth incorrectly sets import path during build time, this is a workaround + # QML_IMPORT_TRACE=1 + # qt.qml.import: addImportPath: "/nix/store/5q4mjar3r9v4drb7wv4rfrw2cgpdp8b4-qtbase-6.9.3/lib/qt-6/qml" + QML_IMPORT_PATH = "${qt6-env}/lib/qt-6/qml"; + } diff --git a/nix/nix.conf b/nix/nix.conf index fe02e7dffe..7c0d3fc8be 100644 --- a/nix/nix.conf +++ b/nix/nix.conf @@ -1,7 +1,6 @@ -# NOTE: If you are in Asia you might want to add https://nix-cache-cn.status.im/ to substituters. -substituters = https://nix-cache.status.im/ https://cache.nixos.org/ -trusted-substituters = https://nix-cache.status.im/ https://cache.nixos.org/ -trusted-public-keys = nix-cache.status.im-1:x/93lOfLU+duPplwMSBR+OlY4+mo+dCN7n0mr4oPwgY= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= +extra-substituters = https://nix-cache.status.im/ +extra-trusted-substituters = https://nix-cache.status.im/ +extra-trusted-public-keys = nix-cache.status.im-1:x/93lOfLU+duPplwMSBR+OlY4+mo+dCN7n0mr4oPwgY= # Some downloads are multiple GB, default is 5 minutes stalled-download-timeout = 3600 connect-timeout = 10 @@ -9,9 +8,6 @@ max-jobs = auto # Build packages if fetching from cache fails. fallback = true # Helps avoid removing currently used dependencies via garbage collection -keep-derivations = true keep-outputs = true -# Some builds on MacOS have issue with sandbox so they are disabled with __noChroot. -sandbox = relaxed # Enable Nix v2 interface. -experimental-features = flakes nix-command +extra-experimental-features = flakes nix-command diff --git a/nix/overlays.nix b/nix/overlays.nix new file mode 100644 index 0000000000..cd1628c6ad --- /dev/null +++ b/nix/overlays.nix @@ -0,0 +1,3 @@ +final: prev: { + fileicon = final.callPackage ./packages/fileicon.nix {}; +} diff --git a/nix/packages/fileicon.nix b/nix/packages/fileicon.nix new file mode 100644 index 0000000000..5b8aca771b --- /dev/null +++ b/nix/packages/fileicon.nix @@ -0,0 +1,36 @@ +{ + lib, + stdenvNoCC, + fetchFromGitHub, + bash, +}: +stdenvNoCC.mkDerivation rec { + pname = "fileicon"; + version = "0.3.5"; + + src = fetchFromGitHub { + owner = "mklement0"; + repo = "fileicon"; + rev = "v${version}"; + hash = "sha256-dFyQYJA/eVgnlfOhD4u/R0HnQieKadW1noY88ve5AAM="; + }; + + dontBuild = true; + + installPhase = '' + runHook preInstall + + install -Dm755 bin/fileicon $out/bin/fileicon + install -Dm644 man/fileicon.1 $out/share/man/man1/fileicon.1 + + runHook postInstall + ''; + + meta = { + description = "macOS CLI for managing custom icons for files and folders"; + homepage = "https://github.com/mklement0/fileicon"; + license = lib.licenses.mit; + platforms = lib.platforms.darwin; + mainProgram = "fileicon"; + }; +}