This commit is contained in:
EthanShoeDev
2025-09-13 22:19:02 -04:00
parent b545a5b1fa
commit 4ca74f4ea2
3 changed files with 2039 additions and 59 deletions

110
flake.nix
View File

@@ -1,4 +1,5 @@
{ {
# nix run nixpkgs#alejandra -- format ./flake.nix
description = "Expo RN devshells (local emulator / remote AVD)"; description = "Expo RN devshells (local emulator / remote AVD)";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
@@ -9,25 +10,31 @@
}; };
}; };
outputs = { self, nixpkgs, android-nixpkgs, ... }: outputs = {
let self,
systems = [ "x86_64-linux" "aarch64-darwin" "x86_64-darwin" ]; nixpkgs,
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: android-nixpkgs,
f { ...
pkgs = import nixpkgs { }: let
inherit system; systems = ["x86_64-linux" "aarch64-darwin" "x86_64-darwin"];
overlays = [ android-nixpkgs.overlays.default ]; forAllSystems = f:
config.allowUnfree = true; # emulator is unfree nixpkgs.lib.genAttrs systems (
}; system:
} f {
); pkgs = import nixpkgs {
in inherit system;
{ overlays = [android-nixpkgs.overlays.default];
devShells = forAllSystems ({ pkgs }: let config.allowUnfree = true; # emulator is unfree
makeAndroidSdk = mode: };
let }
androidSdk = pkgs.androidSdk (sdk: );
if mode == "full" then in {
devShells = forAllSystems ({pkgs}: let
makeAndroidSdk = mode: let
androidSdk = pkgs.androidSdk (
sdk:
if mode == "full"
then
(with sdk; [ (with sdk; [
cmdline-tools-latest cmdline-tools-latest
platform-tools platform-tools
@@ -39,24 +46,23 @@
ndk-26-1-10909125 ndk-26-1-10909125
cmake-3-22-1 cmake-3-22-1
]) ])
else if mode == "remote" then else if mode == "remote"
then
(with sdk; [ (with sdk; [
cmdline-tools-latest # ← required for a valid SDK cmdline-tools-latest # ← required for a valid SDK
platform-tools # adb/fastboot platform-tools # adb/fastboot
]) ])
else else throw "makeAndroidSdk: unknown mode '${mode}'. Use \"full\" or \"remote\"."
throw "makeAndroidSdk: unknown mode '${mode}'. Use \"full\" or \"remote\"." );
);
# Standard path from nixpkgs' androidSdk wrapper # Standard path from nixpkgs' androidSdk wrapper
# https://ryantm.github.io/nixpkgs/languages-frameworks/android/#notes-on-environment-variables-in-android-projects # https://ryantm.github.io/nixpkgs/languages-frameworks/android/#notes-on-environment-variables-in-android-projects
sdkRoot = "${androidSdk}/libexec/android-sdk"; sdkRoot = "${androidSdk}/libexec/android-sdk";
in in {
{ inherit androidSdk sdkRoot;
inherit androidSdk sdkRoot; };
};
fullAndroidSdk = makeAndroidSdk "full"; fullAndroidSdk = makeAndroidSdk "full";
remoteAndroidSdk = makeAndroidSdk "remote"; remoteAndroidSdk = makeAndroidSdk "remote";
defaultPkgs = with pkgs; [ defaultPkgs = with pkgs; [
@@ -68,9 +74,11 @@
watchman watchman
jdk17 jdk17
gradle_8 gradle_8
cmake
ninja
pkg-config
]; ];
in { in {
# Minimal: only universal dev tools you always want # Minimal: only universal dev tools you always want
default = pkgs.mkShell { default = pkgs.mkShell {
packages = defaultPkgs; packages = defaultPkgs;
@@ -78,7 +86,7 @@
# Local emulator: full SDK + AVD bits for API 36 # Local emulator: full SDK + AVD bits for API 36
android-local = pkgs.mkShell { android-local = pkgs.mkShell {
packages = defaultPkgs ++ [ fullAndroidSdk.androidSdk ]; packages = defaultPkgs ++ [fullAndroidSdk.androidSdk];
shellHook = '' shellHook = ''
# Resolve SDK root robustly (libexec first, then share) # Resolve SDK root robustly (libexec first, then share)
_CANDS=( _CANDS=(
@@ -117,21 +125,23 @@
# Remote AVD workflow: no emulator/image; add scrcpy + adb only # Remote AVD workflow: no emulator/image; add scrcpy + adb only
android-remote = pkgs.mkShell { android-remote = pkgs.mkShell {
packages = defaultPkgs ++ [ packages =
remoteAndroidSdk.androidSdk # provides adb/fastboot only defaultPkgs
pkgs.scrcpy ++ [
]; remoteAndroidSdk.androidSdk # provides adb/fastboot only
shellHook = '' pkgs.scrcpy
export ANDROID_SDK_ROOT="${remoteAndroidSdk.sdkRoot}" ];
export ANDROID_HOME="${remoteAndroidSdk.sdkRoot}" shellHook = ''
export PATH="${remoteAndroidSdk.sdkRoot}/platform-tools:$PATH" export ANDROID_SDK_ROOT="${remoteAndroidSdk.sdkRoot}"
hash -r export ANDROID_HOME="${remoteAndroidSdk.sdkRoot}"
echo "Using Nix adb from: $ANDROID_SDK_ROOT" export PATH="${remoteAndroidSdk.sdkRoot}/platform-tools:$PATH"
which -a adb hash -r
adb version || true echo "Using Nix adb from: $ANDROID_SDK_ROOT"
echo "Tip: ssh -N -L 5037:127.0.0.1:5037 user@remote && scrcpy" which -a adb
''; adb version || true
}; echo "Tip: ssh -N -L 5037:127.0.0.1:5037 user@remote && scrcpy"
'';
};
}); });
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,58 @@ name = "uniffi-russh"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # ──────────────────────────────────────────────────────────────────────────────
# Runtime + FFI + SSH deps
# ──────────────────────────────────────────────────────────────────────────────
[dependencies] [dependencies]
uniffi.workspace = true # UniFFI runtime (from your workspace). The `tokio` feature enables
# the `#[uniffi::export(async_runtime = "tokio")]` path so async Rust fns
# surface as Promises on the JS side.
uniffi = { workspace = true, features = ["tokio"] }
# Lightweight error enum derive for FFI-safe error reporting.
thiserror = "1.0.64" thiserror = "1.0.64"
# # Tokio async runtime + IO bits. We use:
# # - rt-multi-thread : multithreaded scheduler
# # - macros : attribute macros (if you ever need #[tokio::test], etc.)
# # - time : timers/sleeps
# # - net : sockets; russh uses this
# # - sync : async Mutex, channels, etc.
# # - io-util : AsyncRead/Write extension traits (write_all/flush)
# tokio = { version = "1.47.1", features = ["rt-multi-thread", "macros", "time", "net", "sync", "io-util"] }
# # Common async ecosystem utilities (not strictly required by our code, but
# # frequently useful and pulled in by transitive deps).
# bytes = "1.10.1"
# futures = "0.3.31"
# # SSH client and keys. `russh` is the client; `russh-keys` handles key types,
# # generation, and OpenSSH (PEM) encoding/decoding.
russh = { version = "0.54.3", default-features = false, features = ["ring", "flate2", "rsa"] }
russh-keys = "0.49.2"
# # Secure RNG for key generation (OsRng).
# rand = "0.8"
# # Handy but currently optional; you can remove it if unused.
# once_cell = "1.21.3"
# # Optional helper for async trait impls; safe to keep even if unused.
# async-trait = "0.1"
# ──────────────────────────────────────────────────────────────────────────────
# Build-time codegen for UniFFI
# ──────────────────────────────────────────────────────────────────────────────
[build-dependencies] [build-dependencies]
# UniFFI build helper to generate bindings at compile time.
uniffi = { workspace = true, features = ["build"] } uniffi = { workspace = true, features = ["build"] }
# ──────────────────────────────────────────────────────────────────────────────
# Library outputs
# ──────────────────────────────────────────────────────────────────────────────
[lib] [lib]
# - cdylib : C-compatible dynamic library (Android/iOS; what RN/JSI loads)
# - staticlib: Static archive (useful for iOS static linking)
# - lib : Normal Rust rlib (unit tests, internal usage)
crate-type = ["cdylib", "staticlib", "lib"] crate-type = ["cdylib", "staticlib", "lib"]