Compare commits
2 Commits
main
...
pr/xcode27
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c89be591ad | ||
|
|
fe4c0ebe24 |
31
.github/workflows/build-and-release.yml
vendored
31
.github/workflows/build-and-release.yml
vendored
@ -30,6 +30,11 @@ on:
|
||||
- ".github/actions/setup-flutter-sdk/action.yml"
|
||||
- ".github/workflows/build-and-release.yml"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
enable_testflight:
|
||||
description: "Build & upload TestFlight (macOS/iOS App Store) artifacts"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@ -49,6 +54,7 @@ jobs:
|
||||
contents: write
|
||||
outputs:
|
||||
should_release: ${{ steps.flags.outputs.should_release }}
|
||||
testflight_enabled: ${{ steps.flags.outputs.testflight_enabled }}
|
||||
release_tag: ${{ steps.meta.outputs.release_tag }}
|
||||
release_title: ${{ steps.meta.outputs.release_title }}
|
||||
release_notes: ${{ steps.meta.outputs.release_notes }}
|
||||
@ -61,6 +67,9 @@ jobs:
|
||||
- name: Determine release mode
|
||||
id: flags
|
||||
shell: bash
|
||||
env:
|
||||
ENABLE_TESTFLIGHT_INPUT: ${{ github.event.inputs.enable_testflight }}
|
||||
ENABLE_TESTFLIGHT_VAR: ${{ vars.ENABLE_TESTFLIGHT }}
|
||||
run: |
|
||||
if [[ "${GITHUB_REF:-}" == refs/tags/v* || "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" || "${GITHUB_REF:-}" == "refs/heads/main" ]]; then
|
||||
echo "should_release=true" >> "$GITHUB_OUTPUT"
|
||||
@ -68,6 +77,16 @@ jobs:
|
||||
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# TestFlight is opt-in (default OFF). Enabled only when explicitly
|
||||
# requested via the workflow_dispatch input or the ENABLE_TESTFLIGHT
|
||||
# repo/org variable. Keeps missing Apple signing secrets from failing
|
||||
# the normal DMG/IPA release path.
|
||||
if [[ "${ENABLE_TESTFLIGHT_INPUT:-}" == "true" || "${ENABLE_TESTFLIGHT_VAR:-}" == "true" ]]; then
|
||||
echo "testflight_enabled=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "testflight_enabled=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Compute release metadata
|
||||
id: meta
|
||||
shell: bash
|
||||
@ -257,12 +276,12 @@ jobs:
|
||||
go-version: "1.24.1"
|
||||
|
||||
- name: Build platform artifacts
|
||||
if: ${{ steps.preflight.outputs.should_build_platform == 'true' && (matrix.release_only != 'true' || env.SHOULD_RELEASE == 'true') }}
|
||||
if: ${{ steps.preflight.outputs.should_build_platform == 'true' && (matrix.release_only != 'true' || env.SHOULD_RELEASE == 'true') && (matrix.package != 'app-store-pkg' || needs.prepare.outputs.testflight_enabled == 'true') }}
|
||||
shell: bash
|
||||
run: bash ./scripts/ci/build_matrix_artifacts.sh "$PLATFORM" "$ARCH" "${{ matrix.package }}" "$SHOULD_RELEASE"
|
||||
|
||||
- name: Upload build artifacts
|
||||
if: ${{ steps.preflight.outputs.should_build_platform == 'true' && (matrix.release_only != 'true' || env.SHOULD_RELEASE == 'true') }}
|
||||
if: ${{ steps.preflight.outputs.should_build_platform == 'true' && (matrix.release_only != 'true' || env.SHOULD_RELEASE == 'true') && (matrix.package != 'app-store-pkg' || needs.prepare.outputs.testflight_enabled == 'true') }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
@ -338,7 +357,7 @@ jobs:
|
||||
|
||||
- name: Load App Store Connect secrets
|
||||
id: vault
|
||||
if: ${{ matrix.target != 'github_release' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
|
||||
if: ${{ matrix.target != 'github_release' && needs.prepare.outputs.testflight_enabled == 'true' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
|
||||
uses: hashicorp/vault-action@v4
|
||||
with:
|
||||
url: ${{ env.VAULT_ADDR }}
|
||||
@ -356,7 +375,7 @@ jobs:
|
||||
kv/data/github-actions/xworkmate-app APP_STORE_CONNECT_API_KEY_P8_BASE64 | APP_STORE_CONNECT_API_KEY_P8_BASE64
|
||||
|
||||
- name: Export App Store Connect secrets
|
||||
if: ${{ matrix.target != 'github_release' }}
|
||||
if: ${{ matrix.target != 'github_release' && needs.prepare.outputs.testflight_enabled == 'true' }}
|
||||
run: |
|
||||
{
|
||||
echo "APPLE_CERT_P12_BASE64=${{ steps.vault.outputs.APPLE_CERT_P12_BASE64 }}"
|
||||
@ -385,13 +404,13 @@ jobs:
|
||||
RELEASE_NOTES: ${{ needs.prepare.outputs.release_notes }}
|
||||
|
||||
- name: Download TestFlight artifact
|
||||
if: ${{ matrix.target != 'github_release' }}
|
||||
if: ${{ matrix.target != 'github_release' && needs.prepare.outputs.testflight_enabled == 'true' }}
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
path: ${{ matrix.artifact_path }}
|
||||
|
||||
- name: Upload to TestFlight
|
||||
if: ${{ matrix.target != 'github_release' }}
|
||||
if: ${{ matrix.target != 'github_release' && needs.prepare.outputs.testflight_enabled == 'true' }}
|
||||
shell: bash
|
||||
run: bash ./scripts/ci/testflight_upload.sh "${{ matrix.testflight_platform }}" "${{ matrix.artifact_path }}"
|
||||
|
||||
@ -39,6 +39,11 @@ post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
|
||||
target.build_configurations.each do |config|
|
||||
# Xcode 27 rejects dependency targets below the app's iOS 15.5 minimum.
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
|
||||
end
|
||||
|
||||
next unless ['Pods-Runner', 'Pods-RunnerTests'].include?(target.name)
|
||||
|
||||
target.build_configurations.each do |config|
|
||||
|
||||
@ -67,6 +67,6 @@ SPEC CHECKSUMS:
|
||||
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
|
||||
WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db
|
||||
|
||||
PODFILE CHECKSUM: 5ab2a375a52a76f419425b2b219d2743259d6f1f
|
||||
PODFILE CHECKSUM: ca16f6ef66890e172b6528d5f0eb390e0410291e
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@ -291,7 +291,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
shellScript = "export PATH=\"$PROJECT_DIR/../scripts/xcode-tools:$PATH\"\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -306,7 +306,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
shellScript = "export PATH=\"$PROJECT_DIR/../scripts/xcode-tools:$PATH\"\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
BA47ED2B244B5E2B99043424 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
platform :osx, '14.0'
|
||||
platform :osx, '15.6'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
@ -97,7 +97,8 @@ post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_macos_build_settings(target)
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '14.0'
|
||||
# Xcode 27 rejects dependency targets below the app's 15.6 minimum.
|
||||
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '15.6'
|
||||
|
||||
next unless ['Pods-Runner', 'Pods-RunnerTests', 'WebRTC-SDK', 'flutter_webrtc'].include?(target.name)
|
||||
|
||||
|
||||
@ -61,6 +61,6 @@ SPEC CHECKSUMS:
|
||||
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
|
||||
WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db
|
||||
|
||||
PODFILE CHECKSUM: 1eb7d5d1472c632b8f775dd34562291c20ae818a
|
||||
PODFILE CHECKSUM: 7804cba3ecbc9953edc70dee53b2ce2b4aeaa013
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@ -371,7 +371,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
|
||||
shellScript = "export PATH=\"$PROJECT_DIR/../scripts/xcode-tools:$PATH\"\necho \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
|
||||
};
|
||||
33CC111E2044C6BF0003C045 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -392,7 +392,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [[ \"${WORKSPACE_DIR:-}\" == *.xcodeproj ]]; then\n echo \"error: XWorkmate macOS builds with CocoaPods plugins must be launched from macos/Runner.xcworkspace, not Runner.xcodeproj.\" >&2\n echo \"error: Close this project, open macos/Runner.xcworkspace in Xcode, and build the shared Runner scheme for My Mac.\" >&2\n echo \"error: Pods targets appearing in the workspace are expected. Only configure signing on the Runner target.\" >&2\n echo \"error: For release packaging, run 'flutter build macos' from the repository root.\" >&2\n exit 1\nfi\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||
shellScript = "export PATH=\"$PROJECT_DIR/../scripts/xcode-tools:$PATH\"\nif [[ \"${WORKSPACE_DIR:-}\" == *.xcodeproj ]]; then\n echo \"error: XWorkmate macOS builds with CocoaPods plugins must be launched from macos/Runner.xcworkspace, not Runner.xcodeproj.\" >&2\n echo \"error: Close this project, open macos/Runner.xcworkspace in Xcode, and build the shared Runner scheme for My Mac.\" >&2\n echo \"error: Pods targets appearing in the workspace are expected. Only configure signing on the Runner target.\" >&2\n echo \"error: For release packaging, run 'flutter build macos' from the repository root.\" >&2\n exit 1\nfi\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||
};
|
||||
8E8C2A3EBAA3461603096C04 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -511,7 +511,7 @@
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
@ -539,7 +539,7 @@
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
@ -567,7 +567,7 @@
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
@ -661,11 +661,13 @@
|
||||
ENABLE_RESOURCE_ACCESS_USB = NO;
|
||||
ENABLE_USER_SELECTED_FILES = readonly;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Xworkmate;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-Wno-ignored-attributes",
|
||||
@ -823,11 +825,13 @@
|
||||
ENABLE_RESOURCE_ACCESS_USB = NO;
|
||||
ENABLE_USER_SELECTED_FILES = readonly;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Xworkmate;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-Wno-ignored-attributes",
|
||||
@ -863,11 +867,13 @@
|
||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||
ENABLE_USER_SELECTED_FILES = readonly;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Xworkmate;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-Wno-ignored-attributes",
|
||||
|
||||
26
scripts/xcode-tools/lipo
Executable file
26
scripts/xcode-tools/lipo
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
real_lipo="$(xcrun --find lipo)"
|
||||
args=("$@")
|
||||
verify_index=-1
|
||||
|
||||
for ((index = 0; index < ${#args[@]}; index++)); do
|
||||
if [[ "${args[index]}" == "-verify_arch" ]]; then
|
||||
verify_index=$index
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Xcode 27 accepts one architecture per -verify_arch invocation. Flutter
|
||||
# passes all requested architectures at once, so verify each one separately.
|
||||
if ((verify_index >= 0 && ${#args[@]} - verify_index > 2)); then
|
||||
command_prefix=("${args[@]:0:verify_index}")
|
||||
architectures=("${args[@]:verify_index+1}")
|
||||
for architecture in "${architectures[@]}"; do
|
||||
"$real_lipo" "${command_prefix[@]}" -verify_arch "$architecture"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec "$real_lipo" "$@"
|
||||
@ -322,9 +322,7 @@ void main() {
|
||||
'xworkmate-no-runtime-main-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final controller = _sandboxController(
|
||||
environmentOverride: const <String, String>{},
|
||||
@ -358,9 +356,7 @@ void main() {
|
||||
'xworkmate-refresh-no-session-one-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final controller = _sandboxController(
|
||||
environmentOverride: const <String, String>{},
|
||||
@ -439,9 +435,7 @@ void main() {
|
||||
'xworkmate-stable-task-selection-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final controller = _sandboxController(
|
||||
environmentOverride: const <String, String>{},
|
||||
@ -1716,9 +1710,7 @@ void main() {
|
||||
'xworkmate-acp-interrupt-artifacts-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localWorkspace.exists()) {
|
||||
await localWorkspace.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localWorkspace);
|
||||
});
|
||||
final fakeGoTaskService = _RecordingGoTaskServiceClient()
|
||||
..onExecuteTask = ((request) async {
|
||||
@ -2017,9 +2009,7 @@ void main() {
|
||||
'xworkmate-acp-handshake-interrupt-artifacts-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localWorkspace.exists()) {
|
||||
await localWorkspace.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localWorkspace);
|
||||
});
|
||||
final fakeGoTaskService = _RecordingGoTaskServiceClient()
|
||||
..updatesBeforeNextOutcome.add(
|
||||
@ -2383,9 +2373,7 @@ void main() {
|
||||
'xworkmate-background-completion-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final fakeGoTaskService = _BlockingGoTaskServiceClient();
|
||||
final controller = _connectedController(
|
||||
@ -2508,9 +2496,7 @@ void main() {
|
||||
'xworkmate-same-prompt-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final fakeGoTaskService = _BlockingGoTaskServiceClient();
|
||||
final controller = _connectedController(
|
||||
@ -2683,9 +2669,7 @@ void main() {
|
||||
'xworkmate-same-prompt-empty-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final fakeGoTaskService = _BlockingGoTaskServiceClient();
|
||||
final controller = _connectedController(
|
||||
@ -2707,9 +2691,7 @@ void main() {
|
||||
continue;
|
||||
}
|
||||
final directory = Directory(workspace);
|
||||
if (await directory.exists()) {
|
||||
await directory.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(directory);
|
||||
}
|
||||
});
|
||||
|
||||
@ -2845,9 +2827,7 @@ void main() {
|
||||
'xworkmate-terminal-failure-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final fakeGoTaskService = _BlockingGoTaskServiceClient();
|
||||
final controller = _connectedController(
|
||||
@ -2925,9 +2905,7 @@ void main() {
|
||||
'xworkmate-empty-output-home-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
final fakeGoTaskService = _BlockingGoTaskServiceClient();
|
||||
final controller = _connectedController(
|
||||
@ -3297,9 +3275,7 @@ void main() {
|
||||
addTearDown(() async {
|
||||
fakeGoTaskService.completeAll();
|
||||
controller.dispose();
|
||||
if (await localHome.exists()) {
|
||||
await localHome.delete(recursive: true);
|
||||
}
|
||||
await _resilientDelete(localHome);
|
||||
});
|
||||
|
||||
for (
|
||||
@ -4902,19 +4878,28 @@ UiFeatureManifest _defaultDesktopManifest() {
|
||||
}
|
||||
|
||||
Future<void> _resilientDelete(Directory dir) async {
|
||||
for (var attempt = 0; attempt < 8; attempt++) {
|
||||
if (!await dir.exists()) {
|
||||
return;
|
||||
}
|
||||
for (var attempt = 0; attempt < 8; attempt++) {
|
||||
try {
|
||||
await dir.delete(recursive: true);
|
||||
return;
|
||||
} catch (error) {
|
||||
// A background flush (e.g. controller dispose still persisting state)
|
||||
// may keep writing into the temp dir, so a recursive delete can race
|
||||
// and fail with "Directory not empty". Retry a few times.
|
||||
debugPrint('Temporary directory delete retry: $error');
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
}
|
||||
}
|
||||
// Best-effort cleanup: never fail a test over leftover temp files; the OS
|
||||
// reclaims the temp directory regardless.
|
||||
try {
|
||||
await dir.delete(recursive: true);
|
||||
} catch (error) {
|
||||
debugPrint('Giving up on temporary directory cleanup: $error');
|
||||
}
|
||||
}
|
||||
|
||||
AppController _sandboxController({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user