1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-09-11 12:05:26 +03:00

Merge pull request #310 from samueldr-wip/fix/more-hermetic-release.nix

More hermetic release.nix and examples
This commit is contained in:
Samuel Dionne-Riel 2021-02-23 21:02:59 -05:00 committed by GitHub
commit 0d9c6ce207
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 87 additions and 229 deletions

View File

@ -1,113 +1,41 @@
let
# Selection of the device can be made either through the environment or through
# using `--argstr device [...]`.
deviceFromEnv = builtins.getEnv "MOBILE_NIXOS_DEVICE";
{ device ? null, configuration ? null, pkgs ? null }@args:
let
# Selection of the configuration can by made either through NIX_PATH,
# through local.nix or as a parameter.
default_configuration =
defaultConfiguration =
let
configPathFromNixPath = (builtins.tryEval <mobile-nixos-configuration>).value;
in
if configPathFromNixPath != false then [ configPathFromNixPath ]
else if (builtins.pathExists ./local.nix) then builtins.trace "WARNING: evaluation includes ./local.nix" [ (import ./local.nix) ]
else []
;
# "a" nixpkgs we're using for its lib.
pkgs' = import <nixpkgs> {};
inherit (pkgs'.lib) optional strings;
inherit (strings) concatStringsSep stringAsChars;
in
{
pkgs ? import <nixpkgs> {}
# The identifier of the device this should be built for.
# (This gets massaged later on)
# This allows using `default.nix` as a pass-through function.
# See usage in examples folder.
, device ? null
, configuration ? default_configuration
# Internally used to tack on configuration by release.nix
, additionalConfiguration ? {}
}:
let
# Either use:
# The given `device`.
# The environment variable.
final_device =
if device != null then device
else if deviceFromEnv == "" then
throw "Please pass a device name or set the MOBILE_NIXOS_DEVICE environment variable."
else deviceFromEnv
;
inherit (import ./lib/release-tools.nix { inherit pkgs; }) evalWith;
# The "default" eval.
eval = evalWith {
device = final_device;
modules = configuration;
inherit additionalConfiguration;
};
# Makes a mostly useless header.
# This is mainly useful for batch evals.
header = str:
let
str' = "* ${str} *";
line = stringAsChars (x: "*") str';
in
builtins.trace (concatStringsSep "\ntrace: " [line str' line])
if configPathFromNixPath != false then
[ configPathFromNixPath ]
else if configuration != null then
[ configuration ]
else if (builtins.pathExists ./local.nix) then
builtins.trace ''
${"\n"}
********************************************
* WARNING: evaluation includes ./local.nix *
********************************************
'' [ (import ./local.nix) ]
else
[]
;
in
(
# Don't break if `device` is not set.
if device == null then (id: id) else
if device ? special
then header "Evaluating: ${device.name}"
else if (builtins.tryEval (builtins.isPath device && builtins.pathExists device)).value
then header "Evaluating device from path: ${toString device}"
else header "Evaluating device: ${device}"
)
{
# The build artifacts from the modules system.
inherit (eval.config.system) build;
# The evaluated config
inherit (eval) config;
# The final pkgs set, usable as -A pkgs.[...] on the CLI.
inherit (eval) pkgs;
# The whole (default) eval
inherit eval;
# Evaluating this whole set is counter-productive.
# It'll put a *bunch* of build products from the misc. inherits we added.
# (We're also using `device` to force the other throw to happen first.)
# TODO : We may want to produce an internal list of available outputs, so that
# each platform can document what it makes available. This would allow
# the message to be more user-friendly by displaying a choice.
__please-fail = throw ''
Cannot directly build for ${final_device}...
Building this whole set is counter-productive, and not likely to be what
is desired.
import ./lib/eval-with-configuration.nix (args // {
configuration = defaultConfiguration;
additionalHelpInstructions = ''
You can build the `-A build.default` attribute to build an empty and
un-configured image. That image can be configured using `local.nix`.
**Note that an unconfigured image may appear to hang at boot.**
** Note that an unconfigured image may appear to hang at boot. **
An alternative is to use one of the `examples` system. They differ in their
configuration. An example that should be building, and working using
cross-compilation is the `examples/hello` system. Read its README for more
information.
$ nix-build examples/hello --argstr device ${final_device} -A build.default
*************************************************************************
* Please also read your device's documentation for further usage notes. *
*************************************************************************
$ nix-build examples/hello --argstr device ${device} -A build.default
'';
}
})

View File

@ -15,7 +15,7 @@ let
devicesDir = ../../../devices;
devicesInfo = symlinkJoin {
name = "devices-metadata";
paths = (map (device: (evalFor device).build.device-metadata) all-devices);
paths = (map (device: (evalFor device).config.system.build.device-metadata) all-devices);
};
in

View File

@ -1,5 +1,7 @@
> **WARNING**: This is still highly experimental. This is not usable as a daily
> driver.
> **WARNING**: This is not usable as a daily driver.
This system is meant as *something* that is usable (barely) on mobile devices,
while waiting for a more proper phone environment to be packaged.
## Building
@ -8,29 +10,12 @@ armv7, aarch64 on aarch64).
(Though the tooling will try to build it through cross-compilation!)
> Note that this has been verified to work on `asus-z00t` on September 24th 2019,
> using nixpkgs commit `d484f2b7fc0834a068e8ace851faa449a03963f5`.
It should be possible to build both boot images via cross-compilation.
## Burning
To burn the image, build the android-burn-tool, then fastboot it.
This will differ depending on the device.
```
nix-build examples/demo/ --argstr device asus-flo -A android-burn-tool
fastboot boot result
```
Once booting, it will show a yellow screen, then either a red or a green screen.
The green screen means that it has found the expected partition to flash. A red
screen means that the user will need to check what is up.
The command will look like:
```
dd if=system.img bs=2M status=progress | bin/ssh-initrd dd of=/dev/[...] bs=2M
```
A common issue with android-based devices is the `system` partition being too
small. To work around this issue, flash to `userdata`.
## Booting
@ -41,4 +26,4 @@ The `boot.img` boot image is expecting to find the system partition using its
label.
It should also be possible to do this entirely statelessly by burning to an SD
card, and fastboot booting the device.
card, and using `fastboot boot`.

View File

@ -1,46 +0,0 @@
# This is intended to be used to produce a bootable `boot.img` with adbd, and
# dropbear enabled. You would, in turn, use it to "flash" a dumb system.img file
# to a partition, like userdata.
#
# *CAUTION* : there is no protection against flashing over the wrong partition.
# Read about the usual pitfalls in the Android section of the documentation.
{ config, lib, pkgs, ... }:
let
device_info = config.mobile.device.info;
in
{
# Ensures we don't quit stage-1
mobile.boot.stage-1.shell.enable = true;
# Only enable `adb` if we know how to.
# FIXME: relies on implementation details. Poor separation of concerns.
mobile.adbd.enable = (config.mobile.system.type == "android") &&
(config.mobile.usb.mode != "gadgetfs" || config.mobile.usb.gadgetfs.functions ? ffs)
;
# Enables networking and ssh in stage-1 !
mobile.boot.stage-1.networking.enable = true;
mobile.boot.stage-1.ssh.enable = true;
mobile.boot.stage-1.fbterm.enable = true;
mobile.boot.stage-1.tasks = [
(pkgs.writeText "adjust-brightness-task.rb" ''
class Tasks::AdjustBrightness < SingletonTask
def initialize()
add_dependency(:Target, :Environment)
add_dependency(:Target, :Graphics)
end
def run()
["lcd-backlight", "wled"].each do |file|
# This can fail to write, ignore...
begin
max = File.read("/sys/class/leds/#{file}/max_brightness").to_i
System.write("/sys/class/leds/#{file}/brightness", (max * 0.1).to_i)
rescue
end
end
end
end
'')
];
}

View File

@ -1,23 +1,11 @@
{ device ? null }:
let
system-build = import ../../. {
inherit device;
configuration = [ { imports = [ ./configuration.nix ]; } ];
};
burn-tool-build = import ../../. {
inherit device;
configuration = [ { imports = [ ./android-burn-tool.nix ]; } ];
};
in
{
inherit (system-build) build;
inherit (system-build.build)
# Android devices
android-bootimg android-device
# QEMU VM
vm
# Depthcharge
disk-image
;
android-burn-tool = burn-tool-build.build.android-bootimg;
}
{ device ? null, pkgs ? null }@args:
import ../../lib/eval-with-configuration.nix (args // {
configuration = [ (import ./configuration.nix) ];
additionalHelpInstructions = ''
You can build the `-A build.default` attribute to build the default output
for your device.
$ nix-build examples/demo --argstr device ${device} -A build.default
'';
})

View File

@ -1,22 +1,11 @@
{ device ? null }:
let
system-build = import ../../. {
inherit device;
configuration = [ { imports = [ ./configuration.nix ]; } ];
};
in
system-build // {
___readme-default = throw ''
Cannot directly build for ${device}...
{ device ? null, pkgs ? null }@args:
import ../../lib/eval-with-configuration.nix (args // {
configuration = [ (import ./configuration.nix) ];
additionalHelpInstructions = ''
You can build the `-A build.default` attribute to build the default output
for your device.
$ nix-build examples/hello --argstr device ${device} -A build.default
*************************************************************************
* Please also read your device's documentation for further usage notes. *
*************************************************************************
'';
}
})

View File

@ -1,11 +1,20 @@
{ device }:
{ device ? null, pkgs ? null }@args:
let
system-build = import ../../. {
inherit device;
configuration = [ (import ./configuration.nix) ];
};
in
{
inherit (system-build) build;
}
import ../../lib/eval-with-configuration.nix (args // {
configuration = [ (import ./configuration.nix) ];
additionalHelpInstructions = ''
The build output to choose depends on the target.
Pinephone, other u-boot, and depthcharge devices:
$ nix-build examples/target-disk-mode --argstr device ${device} -A build.default
Android-based devices:
$ nix-build examples/target-disk-mode --argstr device ${device} -A build.android-bootimg
App "simulator":
$ nix-build examples/target-disk-mode --argstr device uefi-x86_64 -A build.app-simulator
'';
})

View File

@ -1,11 +1,12 @@
{ device ? "uefi-x86_64" }:
{ pkgs ? null }@args:
let
system-build = import ../../../. {
inherit device;
system-build = import ../../../lib/eval-with-configuration.nix (args // {
device = "uefi-x86_64";
configuration = [ { imports = [
../../hello/configuration.nix
./configuration.nix
]; } ];
};
});
in
system-build.build.vm

View File

@ -1,11 +1,12 @@
{ pkgs ? null }@args:
let
device = "uefi-x86_64";
system-build = import ../../../. {
inherit device;
system-build = import ../../../lib/eval-with-configuration.nix (args // {
device = "uefi-x86_64";
configuration = [ { imports = [
../../hello/configuration.nix
./configuration.nix
]; } ];
};
});
in
system-build.build.vm

View File

@ -4,7 +4,7 @@ let
# Original `evalConfig`
evalConfig = import "${toString pkgs.path}/nixos/lib/eval-config.nix";
in
{
rec {
# This should *never* rely on lib or pkgs.
all-devices =
builtins.filter
@ -36,7 +36,7 @@ in
;
};
# These can rely freely on lib, avoir depending on pkgs.
# These can rely freely on lib, avoid depending on pkgs.
withPkgs = pkgs:
let
inherit (pkgs) lib;
@ -67,10 +67,13 @@ in
armv7l-linux = lib.systems.examples.armv7l-hf-multiplatform;
};
# Given a device compatible with `default.nix`, eval.
# Eval with a configuration, for the given device.
evalWithConfiguration = configuration: device: evalWith {
modules = [ configuration ];
inherit device;
};
# The simplest eval for a device, with an empty configuration.
evalFor = evalWithConfiguration {};
evalWithConfiguration = additionalConfiguration: device:
import ../. { inherit device additionalConfiguration; }
;
};
}

View File

@ -105,7 +105,7 @@ let
lib.genAttrs systems (system:
(evalWithConfiguration {
nixpkgs.localSystem = knownSystems.${system};
} device).build.default
} device).config.system.build.default
)
);