1- import { chalk , UsageError } from "@react-native-node-api/cli-utils" ;
1+ import cp from "node:child_process" ;
2+
3+ import { assertFixable } from "@react-native-node-api/cli-utils" ;
24import { getInstalledTargets } from "./rustup.js" ;
35
46export const ANDROID_TARGETS = [
@@ -24,25 +26,23 @@ export const APPLE_TARGETS = [
2426 // "aarch64-apple-ios-macabi", // Catalyst
2527 // "x86_64-apple-ios-macabi", // Catalyst
2628
27- // TODO: Re-enabled these when we know how to install them 🙈
28- /*
29- "aarch64-apple-tvos",
30- "aarch64-apple-tvos-sim",
3129 "aarch64-apple-visionos" ,
3230 "aarch64-apple-visionos-sim" ,
33- */
31+
32+ "aarch64-apple-tvos" ,
33+ // "arm64e-apple-tvos",
34+ "aarch64-apple-tvos-sim" ,
35+ "x86_64-apple-tvos" , // Simulator (despite the missing -sim suffix)
3436
3537 // "aarch64-apple-watchos",
3638 // "aarch64-apple-watchos-sim",
3739 // "arm64_32-apple-watchos",
3840 // "arm64e-apple-darwin",
3941 // "arm64e-apple-ios",
40- // "arm64e-apple-tvos",
4142 // "armv7k-apple-watchos",
4243 // "armv7s-apple-ios",
4344 // "i386-apple-ios",
4445 // "i686-apple-darwin",
45- // "x86_64-apple-tvos",
4646 // "x86_64-apple-watchos-sim",
4747 // "x86_64h-apple-darwin",
4848] as const ;
@@ -51,24 +51,72 @@ export type AppleTargetName = (typeof APPLE_TARGETS)[number];
5151export const ALL_TARGETS = [ ...ANDROID_TARGETS , ...APPLE_TARGETS ] as const ;
5252export type TargetName = ( typeof ALL_TARGETS ) [ number ] ;
5353
54+ const THIRD_TIER_TARGETS : Set < TargetName > = new Set ( [
55+ "aarch64-apple-visionos" ,
56+ "aarch64-apple-visionos-sim" ,
57+
58+ "aarch64-apple-tvos" ,
59+ "aarch64-apple-tvos-sim" ,
60+ "x86_64-apple-tvos" ,
61+ ] ) ;
62+
63+ export function assertNightlyToolchain ( ) {
64+ const toolchainLines = cp
65+ . execFileSync ( "rustup" , [ "toolchain" , "list" ] , {
66+ encoding : "utf-8" ,
67+ } )
68+ . split ( "\n" ) ;
69+
70+ const nightlyLines = toolchainLines . filter ( ( line ) =>
71+ line . startsWith ( "nightly-" ) ,
72+ ) ;
73+ assertFixable (
74+ nightlyLines . length > 0 ,
75+ "You need to use a nightly Rust toolchain" ,
76+ {
77+ command : "rustup toolchain install nightly --component rust-src" ,
78+ } ,
79+ ) ;
80+
81+ const componentLines = cp
82+ . execFileSync ( "rustup" , [ "component" , "list" , "--toolchain" , "nightly" ] , {
83+ encoding : "utf-8" ,
84+ } )
85+ . split ( "\n" ) ;
86+ assertFixable (
87+ componentLines . some ( ( line ) => line === "rust-src (installed)" ) ,
88+ "You need to install the rust-src component for the nightly Rust toolchain" ,
89+ {
90+ command : "rustup toolchain install nightly --component rust-src" ,
91+ } ,
92+ ) ;
93+ }
94+
5495/**
55- * Ensure the targets are installed into the Rust toolchain
96+ * Ensure the targets are either installed into the Rust toolchain or available via nightly Rust toolchain.
5697 * We do this up-front because the error message and fix is very unclear from the failure when missing.
5798 */
58- export function ensureInstalledTargets ( expectedTargets : Set < TargetName > ) {
99+ export function ensureAvailableTargets ( expectedTargets : Set < TargetName > ) {
59100 const installedTargets = getInstalledTargets ( ) ;
60- const missingTargets = new Set ( [
61- ...[ ...expectedTargets ] . filter ( ( target ) => ! installedTargets . has ( target ) ) ,
62- ] ) ;
63- if ( missingTargets . size > 0 ) {
64- // TODO: Ask the user if they want to run this
65- throw new UsageError (
66- `You're missing ${
67- missingTargets . size
68- } targets - to fix this, run:\n\n${ chalk . italic (
69- `rustup target add ${ [ ...missingTargets ] . join ( " " ) } ` ,
70- ) } `,
71- ) ;
101+
102+ const missingInstallableTargets = expectedTargets
103+ . difference ( installedTargets )
104+ . difference ( THIRD_TIER_TARGETS ) ;
105+
106+ assertFixable (
107+ missingInstallableTargets . size === 0 ,
108+ `You need to add these targets to your toolchain: ${ [
109+ ...missingInstallableTargets ,
110+ ] . join ( ", " ) } `,
111+ {
112+ command : `rustup target add ${ [ ...missingInstallableTargets ] . join ( " " ) } ` ,
113+ } ,
114+ ) ;
115+
116+ const expectedThirdTierTargets =
117+ expectedTargets . intersection ( THIRD_TIER_TARGETS ) ;
118+ if ( expectedThirdTierTargets . size > 0 ) {
119+ assertNightlyToolchain ( ) ;
72120 }
73121}
74122
@@ -82,6 +130,10 @@ export function isAppleTarget(target: TargetName): target is AppleTargetName {
82130 return APPLE_TARGETS . includes ( target as ( typeof APPLE_TARGETS ) [ number ] ) ;
83131}
84132
133+ export function isThirdTierTarget ( target : TargetName ) : boolean {
134+ return THIRD_TIER_TARGETS . has ( target ) ;
135+ }
136+
85137export function filterTargetsByPlatform (
86138 targets : Set < TargetName > ,
87139 platform : "android" ,
0 commit comments