Skip to content
Snippets Groups Projects
flake.nix 16.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • {
      description = "The PrivateStorage Mobile application";
      inputs = {
    
        nixpkgs = {
          url = "github:NixOS/nixpkgs?ref=nixos-22.05";
        };
        flake-utils.url = "github:numtide/flake-utils";
        pypi-deps-db = {
          flake = false;
          url = "github:DavHau/pypi-deps-db";
        };
    
        mach-nix-flake = {
          flake = true;
          url = "github:DavHau/mach-nix";
          inputs = {
            nixpkgs.follows = "nixpkgs";
            flake-utils.follows = "flake-utils";
    
            pypi-deps-db.follows = "pypi-deps-db";
    
        buildozerSrc = {
          flake = false;
          url = "github:PrivateStorageio/buildozer?ref=build-without-installing";
        };
        pythonForAndroidSrc = {
          flake = false;
          url = "github:PrivateStorageio/python-for-android?ref=work-on-nixos";
        };
    
      outputs = { self, nixpkgs, flake-utils, mach-nix-flake, buildozerSrc, pythonForAndroidSrc, ... }:
    
        flake-utils.lib.eachSystem [
          "x86_64-linux"
        ] (system: let
    
    
          mach-nix = mach-nix-flake.lib.${system};
    
    Jean-Paul Calderone's avatar
    Jean-Paul Calderone committed
          pkgs = import nixpkgs {
            inherit system;
    
            config = {
              allowUnfree = true;
              android_sdk.accept_license = true;
            };
    
    Jean-Paul Calderone's avatar
    Jean-Paul Calderone committed
          };
    
          python-for-android = mach-nix.buildPythonPackage {
            src = pythonForAndroidSrc;
            requirementsExtra = ''
            sh>=1.10
            '';
          };
          buildozer = mach-nix.buildPythonPackage {
            src = buildozerSrc;
            packagesExtra = [ ];
          };
    
    
          kivy-env = mach-nix.mkPython {
            python = "python39";
            requirements = ''
              kivy
              Pillow
              cython
            '';
    
            packagesExtra = [ python-for-android buildozer ];
    
    
          # THESE MUST AGREE WITH app/app/build.gradle
          #
          # If they do not you will get failures that look something like:
    
          # FAILURE: Build failed with an exception.
          #
          # * What went wrong:
          # Could not determine the dependencies of task ':app:compileReleaseJavaWithJavac'.
          # > Failed to install the following SDK components:
          #       platforms;android-32 Android SDK Platform 32
          #   The SDK directory is not writable (/nix/store/46214a16f22rd7q8vkrhsa907ra0405l-androidsdk/libexec/android-sdk)
    
    
          platformVersion = "31";
    
          buildToolsVersion = "31.0.0";
    
          # Check out pkgs/development/mobile/androidenv/repo.json for
          # nixpkgs-supported versions.
          ndkVersion = "23.0.7123448-rc1";
    
          androidComposition = pkgs.callPackage ./android.nix {
    
            inherit cmakeVersion buildToolsVersion platformVersion ndkVersion;
    
          getBuildInputs = getInputs: xs: builtins.foldl' (accum: drv: (getInputs drv) ++ accum) [] xs;
    
          # Make sure gradle uses the aapt2 from our Android SDK.  Otherwise it
          # downloads one from the internet that doesn't work because it
          # specifies an interpreter (ld.so) that nothing has ensured will
          # exist.
          #
          # Without this you get a stack of build errors that look a bit like:
          #
          # Execution failed for task ':app:processDebugResources'.
          # > Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
          #    > Failed to transform appcompat-1.3.0.aar (androidx.appcompat:appcompat:1.3.0) to match attributes {artifactType=android-compiled-dependencies-resources, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}.
          #       > Execution failed for AarResourcesCompilerTransform: /home/exarkun/.gradle/caches/transforms-3/f5908003b5fc10a9cf0fd543db10ae32/transformed/appcompat-1.3.0.
          #          > AAPT2 aapt2-7.2.1-7984345-linux Daemon #1: Daemon startup failed
          #            This should not happen under normal circumstances, please file an issue if it does.
          ANDROIDSDK = "${androidComposition.androidsdk}/libexec/android-sdk";
          gradle-wrapper = pkgs.writeShellApplication {
            name = "gradle";
            text = ''
            ${pkgs.gradle}/bin/gradle -Pandroid.aapt2FromMavenOverride=${ANDROIDSDK}/build-tools/${buildToolsVersion}/aapt2 "$@"
    
          # packages.host-python = (import nixpkgs { system = "aarch64-linux-android"; }).python3Minimal.override { self = self.packages.host-python; };
    
    
          packages.apk = pkgs.androidenv.buildApp {
    
            name = "PrivateStorage Mobile";
            src = ./app;
            release = false;
    
    
            platformVersions = [ platformVersion ];
    
          apps.emulate = {
    
            type = "app";
            program = let
              emulator = pkgs.androidenv.emulateApp {
                name = "PrivateStorage Mobile";
    
                inherit platformVersion;
    
                abiVersion = "x86_64";
                systemImageType = "default";
    
                package = "MyApp";
                activity = "MainActivity";
              };
            in
    
              "${emulator}/bin/run-test-emulator";
    
          };
          devShells.gradle = pkgs.mkShell rec {
            name = "nix-native";
            version = "2022.11.09";
    
    
            inherit ANDROIDSDK;
    
            ANDROIDNDK = "${ANDROIDSDK}/ndk-bundle";
    
    
            ANDROID_SDK_ROOT = ANDROIDSDK;
            ANDROID_NDK_ROOT = ANDROIDNDK;
    
            # Deprecated but ... :shrug:
            ANDROID_HOME = ANDROIDSDK;
    
    
            ANDROID_PLATFORM_VERSION = "${platformVersion}";
    
    
            # https://nix.dev/tutorials/cross-compilation
    
    
              (python310.withPackages (ps: with ps; [ build ]))
    
    
            shellHook = ''
            # Tell the tools a third time where the SDK and NDK are to be found.
            cat >app/local.properties <<EOF
            # THIS FILE IS AUTOMATICALLY GENERATED
            # DO NOT EDIT
            # YOUR CHANGES WILL BE DESTROYED
    
            sdk.dir=${ANDROIDSDK}
    
          };
    
          devShells.default = self.devShells.${system}.gradle;
    
    
          # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/android.section.md
          # is a good reference for this stuff.
    
          devShells.kivy = pkgs.mkShell rec {
    
            # The docs talk about ANDROID_SDK_ROOT but apparently it has been
            # renamed yet again.
            ANDROIDSDK = "${androidComposition.androidsdk}/libexec/android-sdk";
            ANDROIDNDK = "${ANDROIDSDK}/ndk-bundle";
    
            shellHook = ''
            export PATH="$(echo "$ANDROIDSDK/cmake/${cmakeVersion}".*/bin):$PATH"
            '';
    
    
            buildInputs = with pkgs; [
              android-studio
    
    
              # Kivy and python-for-android depend on:
    
    Jean-Paul Calderone's avatar
    Jean-Paul Calderone committed
              # https://github.com/kivy/python-for-android/blob/v2020.04.29/doc/source/troubleshooting.rst#errors-related-to-java-version
    
    
              # python-for-android recipes all want to download and unpack their
              # own sources!  aaaaaa
              unzip
            ] ++
    
            # Also we need build dependencies for all of the things it is going to
            # build!
            (getBuildInputs (drv: drv.buildInputs) [ openssl libffi python39 ]);
    
    
            nativeBuildInputs =
              with pkgs; getBuildInputs (drv: drv.nativeBuildInputs) [ openssl libffi python39 ];
    
        }) // {
    
          # Python cross-compilation notes.
          #
          # You can get a lot of cross-compiled stuff out of nixpkgs beneath
          # `pkgsCross`.  For example,
          #
          #    pkgsCross.aarch64-android.python3Minimal
          #
          # is just what the name says.  This builds fine with only one small
          # change against current nixpkgs.  However, its extension modules have a
          # harder time.  For example,
          #
          #    pkgsCross.aarch64-android.python3Minimal.pkgs.zfec
          #
          # fails to build because:
          #
          #     running bdist_wheel
          #     Traceback (most recent call last):
          #       File "/build/wheel-0.37.1-source/nix_run_setup", line 8, in <module>
          #         exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
          #       File "setup.py", line 4, in <module>
          #         setup(maintainer=u'Alex Grönholm')
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/__init__.py", line 87, in setup
          #         return distutils.core.setup(**attrs)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 185, in setup
          #         return run_commands(dist)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 201, in run_commands
          #         dist.run_commands()
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 973, in run_commands
          #         self.run_command(cmd)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/dist.py", line 1217, in run_command
          #         super().run_command(command)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 992, in run_command
          #         cmd_obj.run()
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/wheel/bdist_wheel.py", line 295, in run
          #         build_ext = self.reinitialize_command('build_ext')
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/__init__.py", line 200, in reinitialize_command
          #         cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/cmd.py", line 312, in reinitialize_command
          #         return self.distribution.reinitialize_command(command, reinit_subcommands)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 945, in reinitialize_command
          #         command = self.get_command_obj(command_name)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 864, in get_command_obj
          #         klass = self.get_command_class(command)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/dist.py", line 954, in get_command_class
          #         self.cmdclass[command] = cmdclass = ep.load()
          #       File "/nix/store/537cvh8mqdaglc0an8ndmzszllh1lwac-python3-minimal-3.10.8/lib/python3.10/importlib/metadata/__init__.py", line 171, in load
          #         module = import_module(match.group('module'))
          #       File "/nix/store/537cvh8mqdaglc0an8ndmzszllh1lwac-python3-minimal-3.10.8/lib/python3.10/importlib/__init__.py", line 126, in import_module
          #         return _bootstrap._gcd_import(name[level:], package, level)
          #       File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
          #       File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
          #       File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
          #       File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
          #       File "<frozen importlib._bootstrap_external>", line 883, in exec_module
          #       File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/command/build_ext.py", line 26, in <module>
          #         get_config_var("LDSHARED")
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py", line 574, in get_config_var
          #         return get_config_vars().get(name)
          #       File "/nix/store/azdg3l16q2d03g8drgr94bg1069mfzpq-python3.10-bootstrapped-pip-22.2.2/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py", line 553, in get_config_vars
          #         _config_vars = sysconfig.get_config_vars().copy()
          #       File "/nix/store/537cvh8mqdaglc0an8ndmzszllh1lwac-python3-minimal-3.10.8/lib/python3.10/sysconfig.py", line 615, in get_config_vars
          #         _init_posix(_CONFIG_VARS)
          #       File "/nix/store/537cvh8mqdaglc0an8ndmzszllh1lwac-python3-minimal-3.10.8/lib/python3.10/sysconfig.py", line 477, in _init_posix
          #         _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
          #     ModuleNotFoundError: No module named '_sysconfigdata__linux_aarch64-linux-android'
          #
          # Notice that the *build* Python
          # (537cvh8mqdaglc0an8ndmzszllh1lwac-python3-minimal-3.10.8) is trying to
          # load sysconfigdata for the *host* Python - presumably so it can
          # compile the extension correctly.  However, the host Python
          # sysconfigdata module appears to be unavailable to the build Python.
          #
          # Why?  The nixpkgs CPython expression writes the sysconfigdata module
          # for both Pythons (build and host).  It has ``sysconfigdataHook`` that
          # goes to a lot of trouble to compute the right parameters for the host
          # Python and write the data to a properly named source file.
          #
          # However, the build Python and host Pythons each only get one of these
          # modules.  For the build Python it is:
          #
          #   _sysconfigdata__linux_x86_64-linux-gnu.py
          #
          # and the host Python gets:
          #
          #   _sysconfigdata__linux_.py
          #
          # Each of these contains information which is apparently correct for
          # their respective runtime systems.  Then, the nixpkgs CPython
          # expression for building the extension module uses "bootstrap pip"
          # which will respect PYTHONPATH for module search.
          #
          # (Q) Does something put the host Python's _sysconfigdata__linux_.py on
          # the build Python's PYTHONPATH?  What?  How?
          #
          # (Q)
    
          #
          # And now for something completely different.
          #
          # https://crossenv.readthedocs.io/en/latest/ is a tool specifically for
          # this.  It assumes you can cross-compile CPython on your own, though,
          # and then helps you use it to cross-compile extension modules.  Maybe
          # our nixpkgs-cross-compiled CPython would be a good complement?
          #
    
    
          # packages.host-python = pkgsCross.aarch64-android.python3Minimal.withPackages (ps: [
          #   # The nixpkgs zfec has some extra dependencies that we might not
          #   # really care about.  This one is leaner.  Mostly only relevant
          #   # because we have to cross-compile anything here.
          #   (ps.callPackage ./zfec.nix {})
          # ]);
    
          # packages.aarch64-android.host-python310 =
          #   let
          #     pkgs = import nixpkgs {
          #       system = "x86_64-linux";
          #       config = {
          #         allowUnfree = true;
          #         android_sdk.accept_license = true;
          #       };
          #     };
          #   in
          #     (pkgs.pkgsCross.aarch64-android.python310.override {
          #       # Turn off all the things.  Each one might be broken for
          #       # cross-compilation and even if not we don't need them for this build
          #       # Python.  We just need it to report the right platform info.
          #       mimetypesSupport = false;
          #       x11Support = false;
          #       bluezSupport = false;
          #       sqlite = null;
          #       openssl = null;
          #       tzdata = null;
          #       readline = null;
          #     }).overrideAttrs (old: {
          #       # Turn off even more things which aren't parameters to the Python
          #       # expressionThey .
    
          #       # These drag in an aarch64-android bash which fails to build.
          #       preFixup = null;
          #       postPatch = null;
    
          #       # This drags in a -lcrypt dependency which isn't satisfied by Google
          #       # Android Bionic.
          #       LIBS = null;
          #     });
        };