mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2025-12-11 20:15:30 +01:00
[ENG-1840, ENG-1842] Add native dependencies for iOS (#2693)
* Implement dowload of mobile native deps - Add a spinner animation to `pnpm prep` - Change abandoned dependency @iarna/toml with smol-toml - Validate cargo config.toml after generating it from mustache template - Disabled HTTP2 downloads with udici, it is very broken * Initial ios native deps xcframework logic * Remove logic for handling dynamic iOS libs, using static libs now * Fix PATH in build-rust.sh - Remove app.json * Restore crates/images/src/pdf.rs * minor fix .editorconfig * Finally ios successfully compiles with ffmpeg enabled - Change SDCore.podspec to add extra libraries required by ffmpeg - Fix heif linking for ios in config.toml template - Add symlink logic for extra libraries required to compile ios in build-rust.sh
This commit is contained in:
parent
9c9fde2245
commit
b4d1a295ff
@ -24,6 +24,29 @@ rustflags = ["-L", "{{{nativeDeps}}}/lib", "-Csplit-debuginfo=unpacked"]
|
||||
[target.aarch64-apple-darwin.heif]
|
||||
rustc-link-search = ["{{{nativeDeps}}}/lib"]
|
||||
rustc-link-lib = ["heif"]
|
||||
|
||||
{{#hasiOS}}
|
||||
[target.aarch64-apple-ios]
|
||||
rustflags = ["-L", "{{{mobileNativeDeps}}}/aarch64-apple-ios/lib", "-Csplit-debuginfo=unpacked"]
|
||||
|
||||
[target.aarch64-apple-ios.heif]
|
||||
rustc-link-search = ["{{{mobileNativeDeps}}}/aarch64-apple-ios/lib"]
|
||||
rustc-link-lib = ["static:+bundle=heif"]
|
||||
|
||||
[target.aarch64-apple-ios-sim]
|
||||
rustflags = ["-L", "{{{mobileNativeDeps}}}/aarch64-apple-ios-sim/lib", "-Csplit-debuginfo=unpacked"]
|
||||
|
||||
[target.aarch64-apple-ios-sim.heif]
|
||||
rustc-link-search = ["{{{mobileNativeDeps}}}/aarch64-apple-ios-sim/lib"]
|
||||
rustc-link-lib = ["static:+bundle=heif"]
|
||||
|
||||
[target.x86_64-apple-ios]
|
||||
rustflags = ["-L", "{{{mobileNativeDeps}}}/x86_64-apple-ios/lib", "-Csplit-debuginfo=unpacked"]
|
||||
|
||||
[target.x86_64-apple-ios.heif]
|
||||
rustc-link-search = ["{{{mobileNativeDeps}}}/x86_64-apple-ios/lib"]
|
||||
rustc-link-lib = ["static:+bundle=heif"]
|
||||
{{/hasiOS}}
|
||||
{{/isMacOS}}
|
||||
|
||||
{{#isWin}}
|
||||
|
||||
@ -77,6 +77,12 @@ indent_style = space
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
||||
# Ruby
|
||||
# http://www.caliban.org/ruby/rubyguide.shtml#indentation
|
||||
[*.{rb,podspec}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# YAML
|
||||
# http://yaml.org/spec/1.2/2009-07-21/spec.html#id2576668
|
||||
[*.{yaml,yml}]
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -298,6 +298,7 @@ packages/turbo-server/data/
|
||||
packages/turbo-server/uploads/
|
||||
apps/*/stats.html
|
||||
apps/.deps
|
||||
apps/mobile/.deps
|
||||
apps/releases/.vscode
|
||||
apps/desktop/src-tauri/tauri.conf.patch.json
|
||||
apps/desktop/src-tauri/*.dll
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
const path = require('node:path');
|
||||
|
||||
/**
|
||||
* {@type require('prettier').Config}
|
||||
*/
|
||||
@ -24,6 +26,6 @@ module.exports = {
|
||||
],
|
||||
importOrderParserPlugins: ['typescript', 'jsx', 'decorators'],
|
||||
importOrderTypeScriptVersion: '5.0.0',
|
||||
tailwindConfig: './packages/ui/tailwind.config.js',
|
||||
tailwindConfig: path.resolve(path.join(__dirname, 'packages/ui/tailwind.config.js')),
|
||||
plugins: ['@ianvs/prettier-plugin-sort-imports', 'prettier-plugin-tailwindcss']
|
||||
};
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -106,7 +106,5 @@
|
||||
"i18n-ally.keystyle": "flat",
|
||||
// You need to add this to your locale settings file "i18n-ally.translate.google.apiKey": "xxx"
|
||||
"i18n-ally.translate.engines": ["google"],
|
||||
"prettier.configPath": ".prettierrc.js",
|
||||
"prettier.prettierPath": "./node_modules/prettier",
|
||||
"evenBetterToml.taplo.configFile.path": ".taplo.toml"
|
||||
}
|
||||
|
||||
@ -7,9 +7,15 @@ license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version = "1.64"
|
||||
|
||||
[dependencies]
|
||||
# Spacedrive Sub-crates
|
||||
sd-core = { path = "../../../../../core", features = ["mobile"], default-features = false }
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
sd-core = { default-features = false, features = ["mobile"], path = "../../../../../core" }
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
sd-core = { default-features = false, features = [
|
||||
"ffmpeg",
|
||||
"heif",
|
||||
"mobile"
|
||||
], path = "../../../../../core" }
|
||||
|
||||
# Workspace dependencies
|
||||
futures = { workspace = true }
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#![cfg(any(target_os = "android", target_os = "ios"))]
|
||||
|
||||
use futures::{future::join_all, StreamExt};
|
||||
use futures_channel::mpsc;
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
|
||||
@ -1,38 +1,49 @@
|
||||
#
|
||||
# You will probs wanna add `use_frameworks! :linkage => :static` into your `ios/Podfile` as well.
|
||||
#
|
||||
|
||||
require 'json'
|
||||
require "json"
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SDCore'
|
||||
s.version = '0.0.0'
|
||||
s.summary = 'Spacedrive core for React Native'
|
||||
s.description = 'Spacedrive core for React Native'
|
||||
s.author = 'Oscar Beaumont'
|
||||
s.license = 'APGL-3.0'
|
||||
s.platform = :ios, '14.0'
|
||||
s.source = { git: 'https://github.com/spacedriveapp/spacedrive' }
|
||||
s.homepage = 'https://www.spacedrive.com'
|
||||
s.name = "SDCore"
|
||||
s.version = "0.0.0"
|
||||
s.summary = "Spacedrive core for React Native"
|
||||
s.description = "Spacedrive core for React Native"
|
||||
s.author = "Spacedrive Technology Inc"
|
||||
s.license = "AGPL-3.0"
|
||||
s.platform = :ios, "14.0"
|
||||
s.source = { git: "https://github.com/spacedriveapp/spacedrive" }
|
||||
s.homepage = "https://www.spacedrive.com"
|
||||
s.static_framework = true
|
||||
|
||||
s.dependency 'ExpoModulesCore'
|
||||
s.dependency "ExpoModulesCore"
|
||||
|
||||
s.pod_target_xcconfig = {
|
||||
'DEFINES_MODULE' => 'YES',
|
||||
'SWIFT_COMPILATION_MODE' => 'wholemodule'
|
||||
"DEFINES_MODULE" => "YES",
|
||||
"SWIFT_COMPILATION_MODE" => "wholemodule",
|
||||
}
|
||||
|
||||
s.script_phase = {
|
||||
:name => 'Build Spacedrive Core!',
|
||||
:script => 'env -i SPACEDRIVE_CI=$SPACEDRIVE_CI CONFIGURATION=$CONFIGURATION PLATFORM_NAME=$PLATFORM_NAME ${PODS_TARGET_SRCROOT}/build-rust.sh',
|
||||
:execution_position => :before_compile
|
||||
:name => "Build Spacedrive Core!",
|
||||
:script => "exec \"${PODS_TARGET_SRCROOT}/build-rust.sh\"",
|
||||
:execution_position => :before_compile,
|
||||
}
|
||||
|
||||
# Add libraries
|
||||
ffmpeg_libraries = [
|
||||
"-lmp3lame", "-lsoxr", "-ltheora", "-lopus", "-lvorbisenc", "-lx265",
|
||||
"-lpostproc", "-ltheoraenc", "-ltheoradec", "-lde265", "-lvorbisfile",
|
||||
"-logg", "-lSvtAv1Enc", "-lvpx", "-lhdr10plus", "-lx264", "-lvorbis",
|
||||
"-lzimg", "-lsoxr-lsr", "-liconv", "-lbz2", "-llzma"
|
||||
].join(' ')
|
||||
|
||||
# Add frameworks
|
||||
ffmpeg_frameworks = [
|
||||
"-framework AudioToolbox",
|
||||
"-framework VideoToolbox",
|
||||
"-framework AVFoundation"
|
||||
].join(' ')
|
||||
|
||||
s.xcconfig = {
|
||||
'LIBRARY_SEARCH_PATHS' => '"' + JSON.parse(`cargo metadata`)["target_directory"].to_s + '"',
|
||||
'OTHER_LDFLAGS[sdk=iphoneos*]' => '$(inherited) -lsd_mobile_ios',
|
||||
'OTHER_LDFLAGS[sdk=iphonesimulator*]' => '$(inherited) -lsd_mobile_iossim'
|
||||
"LIBRARY_SEARCH_PATHS" => '"' + JSON.parse(`cargo metadata`)["target_directory"].to_s + '"',
|
||||
"OTHER_LDFLAGS[sdk=iphoneos*]" => "$(inherited) -lsd_mobile_ios #{ffmpeg_libraries} #{ffmpeg_frameworks}",
|
||||
"OTHER_LDFLAGS[sdk=iphonesimulator*]" => "$(inherited) -lsd_mobile_iossim #{ffmpeg_libraries} #{ffmpeg_frameworks}",
|
||||
}
|
||||
|
||||
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
||||
|
||||
@ -13,6 +13,22 @@ err() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
symlink_libs() {
|
||||
if [ $# -ne 2 ]; then
|
||||
err "Invalid number of arguments. Usage: symlink_libs <dir1> <dir2>"
|
||||
fi
|
||||
|
||||
if [ ! -d "$1" ]; then
|
||||
err "Directory '$1' does not exist."
|
||||
fi
|
||||
|
||||
if [ ! -d "$2" ]; then
|
||||
err "Directory '$2' does not exist."
|
||||
fi
|
||||
|
||||
find "$1" -type f -name '*.a' -exec ln -sf "{}" "$2" \;
|
||||
}
|
||||
|
||||
if [ -z "${HOME:-}" ]; then
|
||||
HOME="$(CDPATH='' cd -- "$(osascript -e 'set output to (POSIX path of (path to home folder))')" && pwd -P)"
|
||||
export HOME
|
||||
@ -21,35 +37,47 @@ fi
|
||||
echo "Building 'sd-mobile-ios' library..."
|
||||
|
||||
__dirname="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)"
|
||||
DEPS="${__dirname}/../../../.deps/"
|
||||
DEPS="$(CDPATH='' cd -- "$DEPS" && pwd -P)"
|
||||
CARGO_CONFIG="${__dirname}/../../../../../.cargo"
|
||||
CARGO_CONFIG="$(CDPATH='' cd -- "$CARGO_CONFIG" && pwd -P)/config.toml"
|
||||
|
||||
# Ensure target dir exists
|
||||
TARGET_DIRECTORY="${__dirname}/../../../../../target"
|
||||
mkdir -p "$TARGET_DIRECTORY"
|
||||
TARGET_DIRECTORY="$(CDPATH='' cd -- "$TARGET_DIRECTORY" && pwd -P)"
|
||||
|
||||
# if [ "${CONFIGURATION:-}" != "Debug" ]; then
|
||||
# CARGO_FLAGS=--release
|
||||
# export CARGO_FLAGS
|
||||
# fi
|
||||
TARGET_CONFIG=debug
|
||||
if [ "${CONFIGURATION:-}" = "Release" ]; then
|
||||
set -- --release
|
||||
TARGET_CONFIG=release
|
||||
fi
|
||||
|
||||
# Required for CI and for everyone I guess?
|
||||
export PATH="${CARGO_HOME:-"${HOME}/.cargo"}/bin:$PATH"
|
||||
trap 'if [ -e "${CARGO_CONFIG}.bak" ]; then mv "${CARGO_CONFIG}.bak" "$CARGO_CONFIG"; fi' EXIT
|
||||
|
||||
# Required for `cargo` to correctly compile the library
|
||||
RUST_PATH="${CARGO_HOME:-"${HOME}/.cargo"}/bin:$(brew --prefix)/bin:$(env -i /bin/bash --noprofile --norc -c 'echo $PATH')"
|
||||
if [ "${PLATFORM_NAME:-}" = "iphonesimulator" ]; then
|
||||
case "$(uname -m)" in
|
||||
"arm64" | "aarch64") # M series
|
||||
cargo build -p sd-mobile-ios --target aarch64-apple-ios-sim
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_iossim.a "$TARGET_DIRECTORY"/aarch64-apple-ios-sim/debug/libsd_mobile_ios.a
|
||||
sed -i.bak "s|FFMPEG_DIR = { force = true, value = \".*\" }|FFMPEG_DIR = { force = true, value = \"${DEPS}/aarch64-apple-ios-sim\" }|" "$CARGO_CONFIG"
|
||||
env CARGO_FEATURE_STATIC=1 PATH="$RUST_PATH" cargo build -p sd-mobile-ios --target aarch64-apple-ios-sim "$@"
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_iossim.a "${TARGET_DIRECTORY}/aarch64-apple-ios-sim/${TARGET_CONFIG}/libsd_mobile_ios.a"
|
||||
symlink_libs "${DEPS}/aarch64-apple-ios-sim/lib" "$TARGET_DIRECTORY"
|
||||
;;
|
||||
"x86_64") # Intel
|
||||
cargo build -p sd-mobile-ios --target x86_64-apple-ios
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_iossim.a "$TARGET_DIRECTORY"/x86_64-apple-ios/debug/libsd_mobile_ios.a
|
||||
sed -i.bak "s|FFMPEG_DIR = { force = true, value = \".*\" }|FFMPEG_DIR = { force = true, value = \"${DEPS}/x86_64-apple-ios\" }|" "$CARGO_CONFIG"
|
||||
env CARGO_FEATURE_STATIC=1 PATH="$RUST_PATH" cargo build -p sd-mobile-ios --target x86_64-apple-ios "$@"
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_iossim.a "${TARGET_DIRECTORY}/x86_64-apple-ios/${TARGET_CONFIG}/libsd_mobile_ios.a"
|
||||
symlink_libs "${DEPS}/x86_64-apple-ios/lib" "$TARGET_DIRECTORY"
|
||||
;;
|
||||
*)
|
||||
err 'Unsupported architecture.'
|
||||
;;
|
||||
esac
|
||||
else
|
||||
cargo build -p sd-mobile-ios --target aarch64-apple-ios --release
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_ios.a "$TARGET_DIRECTORY"/aarch64-apple-ios/release/libsd_mobile_ios.a
|
||||
sed -i.bak "s|FFMPEG_DIR = { force = true, value = \".*\" }|FFMPEG_DIR = { force = true, value = \"${DEPS}/aarch64-apple-ios\" }|" "$CARGO_CONFIG"
|
||||
env CARGO_FEATURE_STATIC=1 PATH="$RUST_PATH" cargo build -p sd-mobile-ios --target aarch64-apple-ios "$@"
|
||||
lipo -create -output "$TARGET_DIRECTORY"/libsd_mobile_ios.a "${TARGET_DIRECTORY}/aarch64-apple-ios/${TARGET_CONFIG}/libsd_mobile_ios.a"
|
||||
symlink_libs "${DEPS}/aarch64-apple-ios/lib" "$TARGET_DIRECTORY"
|
||||
fi
|
||||
|
||||
@ -74,5 +74,5 @@
|
||||
"eslintConfig": {
|
||||
"root": true
|
||||
},
|
||||
"packageManager": "pnpm@9.7.0"
|
||||
"packageManager": "pnpm@9.9.0"
|
||||
}
|
||||
|
||||
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@ -1169,9 +1169,6 @@ importers:
|
||||
|
||||
scripts:
|
||||
dependencies:
|
||||
'@iarna/toml':
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
archive-wasm:
|
||||
specifier: ^1.7.0
|
||||
version: 1.7.0
|
||||
@ -1181,12 +1178,18 @@ importers:
|
||||
os-proxy-config:
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
plist:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
semver:
|
||||
specifier: ^7.6.3
|
||||
version: 7.6.3
|
||||
smol-toml:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
undici:
|
||||
specifier: ^6.19.7
|
||||
version: 6.19.7
|
||||
specifier: ^6.19.8
|
||||
version: 6.19.8
|
||||
devDependencies:
|
||||
'@babel/core':
|
||||
specifier: ^7.24.0
|
||||
@ -2991,9 +2994,6 @@ packages:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
|
||||
'@iarna/toml@3.0.0':
|
||||
resolution: {integrity: sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q==}
|
||||
|
||||
'@icons-pack/react-simple-icons@9.4.0':
|
||||
resolution: {integrity: sha512-fZtC4Zv53hE+IQE2dJlFt3EB6UOifwTrUNMuEu4hSXemtqMahd05Dpvj2K0j2ewVc+j/ibavud3xjfaMB2Nj7g==}
|
||||
peerDependencies:
|
||||
@ -12270,6 +12270,10 @@ packages:
|
||||
resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
smol-toml@1.3.0:
|
||||
resolution: {integrity: sha512-tWpi2TsODPScmi48b/OQZGi2lgUmBCHy6SZrhi/FdnnHiU1GwebbCfuQuxsC3nHaLwtYeJGPrDZDIeodDOc4pA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
snake-case@3.0.4:
|
||||
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
|
||||
|
||||
@ -13064,8 +13068,8 @@ packages:
|
||||
resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==}
|
||||
engines: {node: '>=14.0'}
|
||||
|
||||
undici@6.19.7:
|
||||
resolution: {integrity: sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==}
|
||||
undici@6.19.8:
|
||||
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
|
||||
engines: {node: '>=18.17'}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.0:
|
||||
@ -15987,8 +15991,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@iarna/toml@3.0.0': {}
|
||||
|
||||
'@icons-pack/react-simple-icons@9.4.0(react@18.2.0)':
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
@ -28240,6 +28242,8 @@ snapshots:
|
||||
|
||||
slugify@1.6.6: {}
|
||||
|
||||
smol-toml@1.3.0: {}
|
||||
|
||||
snake-case@3.0.4:
|
||||
dependencies:
|
||||
dot-case: 3.0.4
|
||||
@ -29078,7 +29082,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@fastify/busboy': 2.1.1
|
||||
|
||||
undici@6.19.7: {}
|
||||
undici@6.19.8: {}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
||||
|
||||
|
||||
@ -18,12 +18,13 @@
|
||||
"trailingComma": "es5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
"smol-toml": "^1.3.0",
|
||||
"archive-wasm": "^1.7.0",
|
||||
"mustache": "^4.2.0",
|
||||
"os-proxy-config": "^1.1.1",
|
||||
"plist": "^3.1.0",
|
||||
"semver": "^7.6.3",
|
||||
"undici": "^6.19.7"
|
||||
"undici": "^6.19.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
|
||||
@ -7,11 +7,14 @@ import { fileURLToPath } from 'node:url'
|
||||
|
||||
import { extractTo } from 'archive-wasm/src/fs.mjs'
|
||||
import * as _mustache from 'mustache'
|
||||
import { parse as parseTOML } from 'smol-toml'
|
||||
|
||||
import { getConst, NATIVE_DEPS_URL, NATIVE_DEPS_ASSETS } from './utils/consts.mjs'
|
||||
import { get } from './utils/fetch.mjs'
|
||||
import { getMachineId } from './utils/machineId.mjs'
|
||||
import { getRustTargetList } from './utils/rustup.mjs'
|
||||
import { symlinkSharedLibsMacOS, symlinkSharedLibsLinux } from './utils/shared.mjs'
|
||||
import { spinTask } from './utils/spinner.mjs'
|
||||
import { which } from './utils/which.mjs'
|
||||
|
||||
if (/^(msys|mingw|cygwin)$/i.test(env.OSTYPE ?? '')) {
|
||||
@ -55,24 +58,78 @@ packages/scripts/${machineId[0] === 'Windows_NT' ? 'setup.ps1' : 'setup.sh'}
|
||||
|
||||
// Directory where the native deps will be downloaded
|
||||
const nativeDeps = path.join(__root, 'apps', '.deps')
|
||||
const mobileNativeDeps = path.join(__root, 'apps', 'mobile', '.deps')
|
||||
await fs.rm(nativeDeps, { force: true, recursive: true })
|
||||
await fs.mkdir(nativeDeps, { mode: 0o750, recursive: true })
|
||||
|
||||
// Native deps for desktop app
|
||||
try {
|
||||
console.log('Downloading Native dependencies...')
|
||||
console.log('Downloading desktop native dependencies...')
|
||||
|
||||
const assetName = getConst(NATIVE_DEPS_ASSETS, machineId)
|
||||
if (assetName == null) throw new Error('NO_ASSET')
|
||||
|
||||
const archiveData = await get(`${NATIVE_DEPS_URL}/${assetName}`)
|
||||
const archiveData = await spinTask(
|
||||
get((__debug && env.NATIVE_DEPS_URL) || `${NATIVE_DEPS_URL}/${assetName}`)
|
||||
)
|
||||
|
||||
await extractTo(archiveData, nativeDeps, {
|
||||
console.log(`Extracting native dependencies...`)
|
||||
await spinTask(
|
||||
extractTo(archiveData, nativeDeps, {
|
||||
chmod: 0o600,
|
||||
recursive: true,
|
||||
overwrite: true,
|
||||
})
|
||||
)
|
||||
} catch (e) {
|
||||
console.error(`Failed to download native dependencies. ${bugWarn}`)
|
||||
console.error(`Failed to download native dependencies.\n${bugWarn}`)
|
||||
if (__debug) console.error(e)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
const rustTargets = await getRustTargetList()
|
||||
const iosTargets = {
|
||||
'aarch64-apple-ios': NATIVE_DEPS_ASSETS.IOS.ios.aarch64,
|
||||
'aarch64-apple-ios-sim': NATIVE_DEPS_ASSETS.IOS.iossim.aarch64,
|
||||
'x86_64-apple-ios': NATIVE_DEPS_ASSETS.IOS.iossim.x86_64,
|
||||
}
|
||||
|
||||
// Native deps for mobile
|
||||
try {
|
||||
const mobileTargets = /** @type {Record<string, string>} */ {}
|
||||
|
||||
if (machineId[0] === 'Darwin')
|
||||
// iOS is only supported on macOS
|
||||
Object.assign(mobileTargets, iosTargets)
|
||||
|
||||
for (const [rustTarget, nativeTarget] of Object.entries(mobileTargets)) {
|
||||
if (!rustTargets.has(rustTarget)) continue
|
||||
console.log(`Downloading mobile native dependencies for ${nativeTarget}...`)
|
||||
|
||||
const specificMobileNativeDeps = path.join(mobileNativeDeps, rustTarget)
|
||||
await fs.rm(specificMobileNativeDeps, { force: true, recursive: true })
|
||||
await fs.mkdir(specificMobileNativeDeps, { mode: 0o750, recursive: true })
|
||||
|
||||
const archiveData = await spinTask(
|
||||
get(
|
||||
(__debug &&
|
||||
env[`NATIVE_DEPS_${rustTarget.replaceAll('-', '_').toUpperCase()}_URL`]) ||
|
||||
`${NATIVE_DEPS_URL}/${nativeTarget}`
|
||||
)
|
||||
)
|
||||
|
||||
console.log(`Extracting native dependencies...`)
|
||||
await spinTask(
|
||||
extractTo(archiveData, specificMobileNativeDeps, {
|
||||
chmod: 0o600,
|
||||
sizeLimit: 256n * 1024n * 1024n,
|
||||
recursive: true,
|
||||
overwrite: true,
|
||||
})
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to download native dependencies for mobile.\n${bugWarn}`)
|
||||
if (__debug) console.error(e)
|
||||
exit(1)
|
||||
}
|
||||
@ -81,17 +138,21 @@ try {
|
||||
try {
|
||||
if (machineId[0] === 'Linux') {
|
||||
console.log(`Symlink shared libs...`)
|
||||
await spinTask(
|
||||
symlinkSharedLibsLinux(__root, nativeDeps).catch(e => {
|
||||
console.error(`Failed to symlink shared libs. ${bugWarn}`)
|
||||
console.error(`Failed to symlink shared libs.\n${bugWarn}`)
|
||||
throw e
|
||||
})
|
||||
)
|
||||
} else if (machineId[0] === 'Darwin') {
|
||||
// This is still required due to how ffmpeg-sys-next builds script works
|
||||
console.log(`Symlink shared libs...`)
|
||||
await symlinkSharedLibsMacOS(__root, nativeDeps).catch(e => {
|
||||
console.error(`Failed to symlink shared libs. ${bugWarn}`)
|
||||
await spinTask(
|
||||
symlinkSharedLibsMacOS(__root, nativeDeps).catch(e => {
|
||||
console.error(`Failed to symlink shared libs.\n${bugWarn}`)
|
||||
throw e
|
||||
})
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
if (__debug) console.error(error)
|
||||
@ -126,15 +187,14 @@ try {
|
||||
break
|
||||
}
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(__root, '.cargo', 'config.toml'),
|
||||
mustache
|
||||
const configData = mustache
|
||||
.render(
|
||||
await fs.readFile(path.join(__root, '.cargo', 'config.toml.mustache'), {
|
||||
encoding: 'utf8',
|
||||
}),
|
||||
{
|
||||
isWin,
|
||||
hasiOS: Object.keys(iosTargets).some(target => rustTargets.has(target)),
|
||||
isMacOS,
|
||||
isLinux,
|
||||
// Escape windows path separator to be compatible with TOML parsing
|
||||
@ -146,14 +206,21 @@ try {
|
||||
)
|
||||
.replaceAll('\\', '\\\\'),
|
||||
nativeDeps: nativeDeps.replaceAll('\\', '\\\\'),
|
||||
mobileNativeDeps: mobileNativeDeps.replaceAll('\\', '\\\\'),
|
||||
hasLLD,
|
||||
}
|
||||
)
|
||||
.replace(/\n\n+/g, '\n'),
|
||||
{ mode: 0o751, flag: 'w+' }
|
||||
)
|
||||
.replace(/\n\n+/g, '\n')
|
||||
|
||||
// Validate generated TOML
|
||||
parseTOML(configData)
|
||||
|
||||
await fs.writeFile(path.join(__root, '.cargo', 'config.toml'), configData, {
|
||||
mode: 0o751,
|
||||
flag: 'w+',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Failed to generate .cargo/config.toml. ${bugWarn}`)
|
||||
console.error(`Failed to generate .cargo/config.toml.\n${bugWarn}`)
|
||||
if (__debug) console.error(error)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { env, exit, umask, platform } from 'node:process'
|
||||
import { setTimeout } from 'node:timers/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import * as toml from '@iarna/toml'
|
||||
import { parse as parseTOML } from 'smol-toml'
|
||||
|
||||
import { waitLockUnlock } from './utils/flock.mjs'
|
||||
import { patchTauri } from './utils/patchTauri.mjs'
|
||||
@ -44,7 +44,7 @@ process.on('SIGINT', cleanUp)
|
||||
// Export environment variables defined in cargo.toml
|
||||
const cargoConfig = await fs
|
||||
.readFile(path.resolve(__root, '.cargo', 'config.toml'), { encoding: 'binary' })
|
||||
.then(toml.parse)
|
||||
.then(parseTOML)
|
||||
if (cargoConfig.env && typeof cargoConfig.env === 'object')
|
||||
for (const [name, value] of Object.entries(cargoConfig.env)) if (!env[name]) env[name] = value
|
||||
|
||||
|
||||
@ -20,6 +20,15 @@ export const NATIVE_DEPS_ASSETS = {
|
||||
x86_64: 'native-deps-x86_64-windows-gnu.tar.xz ',
|
||||
aarch64: 'native-deps-aarch64-windows-gnu.tar.xz',
|
||||
},
|
||||
IOS: {
|
||||
iossim: {
|
||||
x86_64: 'native-deps-x86_64-iossim-apple.tar.xz',
|
||||
aarch64: 'native-deps-aarch64-iossim-apple.tar.xz',
|
||||
},
|
||||
ios: {
|
||||
aarch64: 'native-deps-aarch64-ios-apple.tar.xz',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -15,7 +15,7 @@ const cacheDir = joinPath(__dirname, '.tmp')
|
||||
|
||||
/** @type {Agent.Options} */
|
||||
const agentOpts = {
|
||||
allowH2: true,
|
||||
allowH2: !!env.HTTP2,
|
||||
connect: { timeout: CONNECT_TIMEOUT },
|
||||
connectTimeout: CONNECT_TIMEOUT,
|
||||
autoSelectFamily: true,
|
||||
@ -45,7 +45,7 @@ async function getCache(resource, headers) {
|
||||
let header
|
||||
|
||||
// Don't cache in CI
|
||||
if (env.CI === 'true') return null
|
||||
if (env.CI === 'true' || env.NO_CACHE === 'true') return null
|
||||
|
||||
if (headers)
|
||||
resource += Array.from(headers.entries())
|
||||
@ -145,6 +145,7 @@ export async function get(resource, headers, preferCache) {
|
||||
|
||||
if (cache?.header) headers.append(...cache.header)
|
||||
|
||||
if (__debug) console.log(`Downloading ${resource} ${cache?.data ? ' (cached)' : ''}...`)
|
||||
const response = await fetch(resource, { dispatcher, headers })
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
12
scripts/utils/rustup.mjs
Normal file
12
scripts/utils/rustup.mjs
Normal file
@ -0,0 +1,12 @@
|
||||
import { exec as execCb } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
const exec = promisify(execCb)
|
||||
|
||||
/**
|
||||
* Get the list of rust targets
|
||||
* @returns {Promise<Set<string>>}
|
||||
*/
|
||||
export async function getRustTargetList() {
|
||||
return new Set((await exec('rustup target list --installed')).stdout.split('\n'))
|
||||
}
|
||||
44
scripts/utils/spinner.mjs
Normal file
44
scripts/utils/spinner.mjs
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Simple function that implements a spinner animation in the terminal.
|
||||
* It receives an AbortController as argument and return a promise that resolves when the AbortController is signaled.
|
||||
* @param {AbortController} abortController
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function spinnerAnimation(abortController) {
|
||||
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
||||
let frameIndex = 0
|
||||
|
||||
return new Promise(resolve => {
|
||||
const intervalId = setInterval(() => {
|
||||
process.stdout.write(`\r${frames[frameIndex++]}`)
|
||||
frameIndex %= frames.length
|
||||
}, 100)
|
||||
|
||||
const onAbort = () => {
|
||||
clearInterval(intervalId)
|
||||
process.stdout.write('\r \r') // Clear spinner
|
||||
resolve()
|
||||
}
|
||||
|
||||
if (abortController.signal.aborted) {
|
||||
onAbort()
|
||||
} else {
|
||||
abortController.signal.addEventListener('abort', onAbort)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a long running task with a spinner animation.
|
||||
* @template T
|
||||
* @param {Promise<T>} promise
|
||||
* @returns {Promise<T>}
|
||||
*/
|
||||
export async function spinTask(promise) {
|
||||
const spinnerControl = new AbortController()
|
||||
const [, result] = await Promise.all([
|
||||
spinnerAnimation(spinnerControl),
|
||||
promise.finally(() => spinnerControl.abort('Task is over')),
|
||||
])
|
||||
return result
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user