@invarn/cibuild 2.9.2 → 2.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +97 -12
- package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts +42 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts.map +1 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.js +140 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts +11 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/cocoapods-deployment-floor.test.js +176 -0
- package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -1
- package/dist/src/yaml/steps/ios-deps.js +2 -0
- package/dist/src/yaml/steps/xcode-derived-data.test.js +18 -1
- package/dist/src/yaml/steps/xcode-simulator-archs.d.ts +53 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.js +98 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts +21 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-simulator-archs.test.js +155 -0
- package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
- package/dist/src/yaml/steps/xcode.js +31 -2
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* After `pod install`: raise every pod target whose deployment target is below
|
|
3
|
+
* the app's own to the app's.
|
|
4
|
+
*
|
|
5
|
+
* A pod target below iOS 9 links ARC Lite, and Xcode 14.3 removed
|
|
6
|
+
* `libarclite`: `clang: error: SDK does not contain 'libarclite' at …
|
|
7
|
+
* libarclite_iphonesimulator.a; try increasing the minimum deployment
|
|
8
|
+
* target`. CocoaPods gives each pod target the deployment target its podspec
|
|
9
|
+
* declares, so an old pod (SwiftLinkPreview 3.1.0, `ios: '8.0'`) stops an app
|
|
10
|
+
* that itself targets iOS 12 (YuigaWada/MissCat, nightly-baseline issue 53).
|
|
11
|
+
* The usual fix lives in the app's own Podfile, a `post_install` that raises
|
|
12
|
+
* the pods; a repository whose Podfile has none cannot build under any
|
|
13
|
+
* current Xcode.
|
|
14
|
+
*
|
|
15
|
+
* RULED 2026-10-01 (Alex): raise every pod target below the app target's own
|
|
16
|
+
* deployment target to it, in the step, always. Never the app target, never
|
|
17
|
+
* past what the app promises: the floor is the lowest deployment target among
|
|
18
|
+
* the user targets CocoaPods integrated (each found by its `Pods-*.xcconfig`
|
|
19
|
+
* base configuration), so an extension that targets lower than the app keeps
|
|
20
|
+
* its pods buildable for it. A pod cannot run below the app that embeds it, so
|
|
21
|
+
* the raise changes nothing a user of the app could observe. Only the
|
|
22
|
+
* generated `Pods/*.xcodeproj` is edited; it is the checkout's, never
|
|
23
|
+
* committed back.
|
|
24
|
+
*
|
|
25
|
+
* Measured on a clone, Xcode 26.4, 2026-10-01: MissCat @ 574355469ebb, app
|
|
26
|
+
* targets MissCat and MissCatShare at 12.0, 74 pod build configurations raised
|
|
27
|
+
* from 8.0–9.3; SwiftLinkPreview then compiled at ios12.0-simulator and the
|
|
28
|
+
* build log never mentioned libarclite.
|
|
29
|
+
*
|
|
30
|
+
* Never a reason the step fails: a Ruby that cannot load `xcodeproj`, a Pods
|
|
31
|
+
* project it cannot read, a workspace it cannot find — each is a line in the
|
|
32
|
+
* log and the pods as CocoaPods left them.
|
|
33
|
+
*/
|
|
34
|
+
/** Ruby; argv[0] is the Pods directory. Prints what it read and what it raised. */
|
|
35
|
+
export declare const POD_DEPLOYMENT_FLOOR_SOURCE: string;
|
|
36
|
+
/**
|
|
37
|
+
* Bash lines that run the raise in the step's directory, after `pod install`.
|
|
38
|
+
* They expect `$USE_BUNDLE_EXEC` and `$BUNDLE_CMD` from the step, and never
|
|
39
|
+
* fail it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function podDeploymentFloorLines(): string[];
|
|
42
|
+
//# sourceMappingURL=cocoapods-deployment-floor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cocoapods-deployment-floor.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cocoapods-deployment-floor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,mFAAmF;AACnF,eAAO,MAAM,2BAA2B,EAAE,MAgEzC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAkClD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* After `pod install`: raise every pod target whose deployment target is below
|
|
3
|
+
* the app's own to the app's.
|
|
4
|
+
*
|
|
5
|
+
* A pod target below iOS 9 links ARC Lite, and Xcode 14.3 removed
|
|
6
|
+
* `libarclite`: `clang: error: SDK does not contain 'libarclite' at …
|
|
7
|
+
* libarclite_iphonesimulator.a; try increasing the minimum deployment
|
|
8
|
+
* target`. CocoaPods gives each pod target the deployment target its podspec
|
|
9
|
+
* declares, so an old pod (SwiftLinkPreview 3.1.0, `ios: '8.0'`) stops an app
|
|
10
|
+
* that itself targets iOS 12 (YuigaWada/MissCat, nightly-baseline issue 53).
|
|
11
|
+
* The usual fix lives in the app's own Podfile, a `post_install` that raises
|
|
12
|
+
* the pods; a repository whose Podfile has none cannot build under any
|
|
13
|
+
* current Xcode.
|
|
14
|
+
*
|
|
15
|
+
* RULED 2026-10-01 (Alex): raise every pod target below the app target's own
|
|
16
|
+
* deployment target to it, in the step, always. Never the app target, never
|
|
17
|
+
* past what the app promises: the floor is the lowest deployment target among
|
|
18
|
+
* the user targets CocoaPods integrated (each found by its `Pods-*.xcconfig`
|
|
19
|
+
* base configuration), so an extension that targets lower than the app keeps
|
|
20
|
+
* its pods buildable for it. A pod cannot run below the app that embeds it, so
|
|
21
|
+
* the raise changes nothing a user of the app could observe. Only the
|
|
22
|
+
* generated `Pods/*.xcodeproj` is edited; it is the checkout's, never
|
|
23
|
+
* committed back.
|
|
24
|
+
*
|
|
25
|
+
* Measured on a clone, Xcode 26.4, 2026-10-01: MissCat @ 574355469ebb, app
|
|
26
|
+
* targets MissCat and MissCatShare at 12.0, 74 pod build configurations raised
|
|
27
|
+
* from 8.0–9.3; SwiftLinkPreview then compiled at ios12.0-simulator and the
|
|
28
|
+
* build log never mentioned libarclite.
|
|
29
|
+
*
|
|
30
|
+
* Never a reason the step fails: a Ruby that cannot load `xcodeproj`, a Pods
|
|
31
|
+
* project it cannot read, a workspace it cannot find — each is a line in the
|
|
32
|
+
* log and the pods as CocoaPods left them.
|
|
33
|
+
*/
|
|
34
|
+
/** Ruby; argv[0] is the Pods directory. Prints what it read and what it raised. */
|
|
35
|
+
export const POD_DEPLOYMENT_FLOOR_SOURCE = String.raw `
|
|
36
|
+
require 'xcodeproj'
|
|
37
|
+
pods_dir = File.expand_path(ARGV[0] || 'Pods')
|
|
38
|
+
pod_projects = Dir.glob(File.join(pods_dir, '*.xcodeproj'))
|
|
39
|
+
if pod_projects.empty?
|
|
40
|
+
puts "No Pods project under #{pods_dir}; pods' deployment targets left as they are"
|
|
41
|
+
exit 0
|
|
42
|
+
end
|
|
43
|
+
root = File.expand_path('..', pods_dir)
|
|
44
|
+
KEYS = %w[IPHONEOS_DEPLOYMENT_TARGET MACOSX_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET WATCHOS_DEPLOYMENT_TARGET XROS_DEPLOYMENT_TARGET]
|
|
45
|
+
def version_of(value)
|
|
46
|
+
value.to_s.strip =~ /\A\d+(\.\d+){0,2}\z/ ? Gem::Version.new(value.to_s.strip) : nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
floors = {}
|
|
50
|
+
Dir.glob(File.join(root, '*.xcworkspace')).each do |ws|
|
|
51
|
+
Xcodeproj::Workspace.new_from_xcworkspace(ws).file_references.each do |ref|
|
|
52
|
+
path = File.expand_path(ref.absolute_path(File.expand_path('..', ws)))
|
|
53
|
+
next if path.start_with?(pods_dir + File::SEPARATOR) || !File.directory?(path)
|
|
54
|
+
project = Xcodeproj::Project.open(path)
|
|
55
|
+
project.native_targets.each do |target|
|
|
56
|
+
target.build_configurations.each do |config|
|
|
57
|
+
base = config.base_configuration_reference
|
|
58
|
+
next unless base && File.basename(base.path.to_s) =~ /\APods-.*\.xcconfig\z/
|
|
59
|
+
project_settings = project.build_configuration_list.build_settings(config.name) || {}
|
|
60
|
+
KEYS.each do |key|
|
|
61
|
+
v = version_of(config.build_settings[key]) || version_of(project_settings[key])
|
|
62
|
+
next unless v
|
|
63
|
+
floors[key] = v if floors[key].nil? || v < floors[key]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
if floors.empty?
|
|
70
|
+
puts "No app target CocoaPods integrated declares a deployment target; pods' deployment targets left as they are"
|
|
71
|
+
exit 0
|
|
72
|
+
end
|
|
73
|
+
puts "The app's own deployment target: #{floors.map { |k, v| "#{k} #{v}" }.join(', ')}"
|
|
74
|
+
|
|
75
|
+
raised = []
|
|
76
|
+
pod_projects.each do |path|
|
|
77
|
+
project = Xcodeproj::Project.open(path)
|
|
78
|
+
changed = false
|
|
79
|
+
project.targets.each do |target|
|
|
80
|
+
next if target.name.start_with?('Pods-')
|
|
81
|
+
target.build_configurations.each do |config|
|
|
82
|
+
floors.each do |key, floor|
|
|
83
|
+
v = version_of(config.build_settings[key])
|
|
84
|
+
next unless v && v < floor
|
|
85
|
+
config.build_settings[key] = floor.to_s
|
|
86
|
+
raised << "#{target.name} #{v}"
|
|
87
|
+
changed = true
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
project.save if changed
|
|
92
|
+
end
|
|
93
|
+
if raised.empty?
|
|
94
|
+
puts "No pod target is below it"
|
|
95
|
+
else
|
|
96
|
+
names = raised.uniq
|
|
97
|
+
puts "Raised #{names.size} pod target(s) below the app's deployment target to it: #{names.join(', ')}"
|
|
98
|
+
end
|
|
99
|
+
`;
|
|
100
|
+
/**
|
|
101
|
+
* Bash lines that run the raise in the step's directory, after `pod install`.
|
|
102
|
+
* They expect `$USE_BUNDLE_EXEC` and `$BUNDLE_CMD` from the step, and never
|
|
103
|
+
* fail it.
|
|
104
|
+
*/
|
|
105
|
+
export function podDeploymentFloorLines() {
|
|
106
|
+
return [
|
|
107
|
+
"# Raise pods below the app's own deployment target to it — see",
|
|
108
|
+
'# cocoapods-deployment-floor.ts. Never fails the step.',
|
|
109
|
+
'if [ -d Pods ]; then',
|
|
110
|
+
' POD_FLOOR_SCRIPT="$(mktemp -t cibuild-pod-floor).rb"',
|
|
111
|
+
` cat > "$POD_FLOOR_SCRIPT" << 'CIBUILD_POD_FLOOR_EOF'`,
|
|
112
|
+
POD_DEPLOYMENT_FLOOR_SOURCE.trim(),
|
|
113
|
+
'CIBUILD_POD_FLOOR_EOF',
|
|
114
|
+
' # A Ruby that can load xcodeproj: the bundle CocoaPods ran from, the',
|
|
115
|
+
" # ruby on PATH, or a Homebrew pod wrapper's own interpreter and gems.",
|
|
116
|
+
' POD_FLOOR_RUN=""',
|
|
117
|
+
' if [ "$USE_BUNDLE_EXEC" = "true" ] && $BUNDLE_CMD exec ruby -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
|
|
118
|
+
' POD_FLOOR_RUN="$BUNDLE_CMD exec ruby"',
|
|
119
|
+
' elif ruby -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
|
|
120
|
+
' POD_FLOOR_RUN="ruby"',
|
|
121
|
+
' else',
|
|
122
|
+
' POD_WRAPPER="$(command -v pod 2>/dev/null || true)"',
|
|
123
|
+
' POD_GEM_HOME="$( [ -n "$POD_WRAPPER" ] && sed -n \'s/^GEM_HOME="\\([^"]*\\)".*/\\1/p\' "$POD_WRAPPER" | head -n 1)"',
|
|
124
|
+
' POD_REAL="$( [ -n "$POD_WRAPPER" ] && sed -n \'s/.*exec "\\([^"]*\\)".*/\\1/p\' "$POD_WRAPPER" | head -n 1)"',
|
|
125
|
+
' POD_RUBY="$( [ -n "$POD_REAL" ] && [ -f "$POD_REAL" ] && head -n 1 "$POD_REAL" | sed -n \'s/^#!//p\')"',
|
|
126
|
+
' if [ -n "$POD_GEM_HOME" ] && [ -n "$POD_RUBY" ] && GEM_HOME="$POD_GEM_HOME" $POD_RUBY -e "require %q(xcodeproj)" >/dev/null 2>&1; then',
|
|
127
|
+
' POD_FLOOR_RUN="env GEM_HOME=$POD_GEM_HOME $POD_RUBY"',
|
|
128
|
+
' fi',
|
|
129
|
+
' fi',
|
|
130
|
+
' if [ -n "$POD_FLOOR_RUN" ]; then',
|
|
131
|
+
' $POD_FLOOR_RUN "$POD_FLOOR_SCRIPT" Pods || echo "⚠️ Could not raise pods to the app\'s deployment target; left as CocoaPods wrote them"',
|
|
132
|
+
' else',
|
|
133
|
+
' echo "⚠️ No Ruby here loads xcodeproj; pods\' deployment targets left as CocoaPods wrote them"',
|
|
134
|
+
' fi',
|
|
135
|
+
' rm -f "$POD_FLOOR_SCRIPT"',
|
|
136
|
+
'fi',
|
|
137
|
+
'',
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=cocoapods-deployment-floor.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pods below the app's own deployment target are raised to it, after pod
|
|
3
|
+
* install, and nothing else moves. Witness: YuigaWada/MissCat (nightly-baseline
|
|
4
|
+
* issue 53) — SwiftLinkPreview 3.1.0 at iOS 8.0 linked libarclite, which
|
|
5
|
+
* Xcode 14.3 removed, in an app that targets iOS 12.0.
|
|
6
|
+
*
|
|
7
|
+
* The Ruby runs for real against projects the xcodeproj gem writes, when this
|
|
8
|
+
* machine's ruby can load it; otherwise those tests are skipped and say so.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cocoapods-deployment-floor.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cocoapods-deployment-floor.test.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cocoapods-deployment-floor.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pods below the app's own deployment target are raised to it, after pod
|
|
3
|
+
* install, and nothing else moves. Witness: YuigaWada/MissCat (nightly-baseline
|
|
4
|
+
* issue 53) — SwiftLinkPreview 3.1.0 at iOS 8.0 linked libarclite, which
|
|
5
|
+
* Xcode 14.3 removed, in an app that targets iOS 12.0.
|
|
6
|
+
*
|
|
7
|
+
* The Ruby runs for real against projects the xcodeproj gem writes, when this
|
|
8
|
+
* machine's ruby can load it; otherwise those tests are skipped and say so.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, test, expect } from '@jest/globals';
|
|
11
|
+
import { execFileSync } from 'node:child_process';
|
|
12
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { POD_DEPLOYMENT_FLOOR_SOURCE, podDeploymentFloorLines } from './cocoapods-deployment-floor.js';
|
|
16
|
+
import { CocoapodsInstallStepExecutor } from './ios-deps.js';
|
|
17
|
+
import { testConfig } from './test-config.js';
|
|
18
|
+
const hasXcodeproj = (() => {
|
|
19
|
+
try {
|
|
20
|
+
execFileSync('ruby', ['-e', 'require %q(xcodeproj)'], { stdio: 'ignore' });
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
/**
|
|
28
|
+
* MissCat's shape: an app at 12.0 and a share extension at 11.0, both
|
|
29
|
+
* integrated by CocoaPods; pods at 8.0 (SwiftLinkPreview), 11.0 and 13.0; a
|
|
30
|
+
* library target in the app's project that CocoaPods does not integrate, at 8.0.
|
|
31
|
+
*/
|
|
32
|
+
const FIXTURE = String.raw `
|
|
33
|
+
require 'xcodeproj'
|
|
34
|
+
require 'fileutils'
|
|
35
|
+
dir = ARGV[0]
|
|
36
|
+
FileUtils.mkdir_p(File.join(dir, 'Pods', 'Target Support Files', 'Pods-App'))
|
|
37
|
+
app = Xcodeproj::Project.new(File.join(dir, 'App.xcodeproj'))
|
|
38
|
+
xc = app.new_file('Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig')
|
|
39
|
+
[['App', :application, '12.0', true], ['Share', :app_extension, '11.0', true], ['Unpodded', :framework, '8.0', false]].each do |name, type, dt, podded|
|
|
40
|
+
t = app.new_target(type, name, :ios, dt)
|
|
41
|
+
t.build_configurations.each { |c| c.base_configuration_reference = xc if podded }
|
|
42
|
+
end
|
|
43
|
+
app.save
|
|
44
|
+
pods = Xcodeproj::Project.new(File.join(dir, 'Pods', 'Pods.xcodeproj'))
|
|
45
|
+
pods.new_target(:framework, 'Pods-App', :ios, '12.0')
|
|
46
|
+
[['SwiftLinkPreview', '8.0'], ['MidPod', '11.0'], ['NewPod', '13.0']].each { |n, dt| pods.new_target(:framework, n, :ios, dt) }
|
|
47
|
+
pods.save
|
|
48
|
+
ws = Xcodeproj::Workspace.new(nil)
|
|
49
|
+
ws << 'App.xcodeproj'
|
|
50
|
+
ws << 'Pods/Pods.xcodeproj'
|
|
51
|
+
ws.save_as(File.join(dir, 'App.xcworkspace'))
|
|
52
|
+
`;
|
|
53
|
+
const DUMP = String.raw `
|
|
54
|
+
require 'xcodeproj'
|
|
55
|
+
p = Xcodeproj::Project.open(ARGV[0])
|
|
56
|
+
p.targets.each { |t| t.build_configurations.each { |c| puts "#{t.name} #{c.name} #{c.build_settings['IPHONEOS_DEPLOYMENT_TARGET']}" } }
|
|
57
|
+
`;
|
|
58
|
+
const ruby = (source, args, cwd) => {
|
|
59
|
+
const dir = mkdtempSync(join(tmpdir(), 'pod-floor-rb-'));
|
|
60
|
+
try {
|
|
61
|
+
const f = join(dir, 's.rb');
|
|
62
|
+
writeFileSync(f, source);
|
|
63
|
+
return execFileSync('ruby', [f, ...args], { encoding: 'utf8', cwd });
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
rmSync(dir, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
(hasXcodeproj ? describe : describe.skip)('the raise, on projects the xcodeproj gem wrote', () => {
|
|
70
|
+
const withFixture = (fn) => {
|
|
71
|
+
const dir = mkdtempSync(join(tmpdir(), 'pod-floor-'));
|
|
72
|
+
try {
|
|
73
|
+
ruby(FIXTURE, [dir]);
|
|
74
|
+
fn(dir);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
rmSync(dir, { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const settings = (projectPath) => Object.fromEntries(ruby(DUMP, [projectPath])
|
|
81
|
+
.trim()
|
|
82
|
+
.split('\n')
|
|
83
|
+
.map((l) => {
|
|
84
|
+
const [t, c, v] = l.split(' ');
|
|
85
|
+
return [`${t} ${c}`, v];
|
|
86
|
+
}));
|
|
87
|
+
test('raises pods below the lowest integrated user target to it, and only those', () => {
|
|
88
|
+
withFixture((dir) => {
|
|
89
|
+
const out = ruby(POD_DEPLOYMENT_FLOOR_SOURCE, ['Pods'], dir);
|
|
90
|
+
const pods = settings(join(dir, 'Pods', 'Pods.xcodeproj'));
|
|
91
|
+
// The floor is the share extension's 11.0, the lowest the app promises.
|
|
92
|
+
expect(pods['SwiftLinkPreview Debug']).toBe('11.0');
|
|
93
|
+
expect(pods['SwiftLinkPreview Release']).toBe('11.0');
|
|
94
|
+
expect(pods['MidPod Debug']).toBe('11.0');
|
|
95
|
+
expect(pods['NewPod Debug']).toBe('13.0');
|
|
96
|
+
expect(pods['Pods-App Debug']).toBe('12.0');
|
|
97
|
+
expect(out).toContain('IPHONEOS_DEPLOYMENT_TARGET 11.0');
|
|
98
|
+
expect(out).toContain('Raised 1 pod target(s)');
|
|
99
|
+
expect(out).toContain('SwiftLinkPreview 8.0');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
test("never touches the app's own project, not even a target CocoaPods does not integrate", () => {
|
|
103
|
+
withFixture((dir) => {
|
|
104
|
+
const before = readFileSync(join(dir, 'App.xcodeproj', 'project.pbxproj'), 'utf8');
|
|
105
|
+
ruby(POD_DEPLOYMENT_FLOOR_SOURCE, ['Pods'], dir);
|
|
106
|
+
expect(readFileSync(join(dir, 'App.xcodeproj', 'project.pbxproj'), 'utf8')).toBe(before);
|
|
107
|
+
// ...and the unintegrated 8.0 library is not the floor: the pod was raised.
|
|
108
|
+
expect(settings(join(dir, 'Pods', 'Pods.xcodeproj'))['SwiftLinkPreview Debug']).toBe('11.0');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
test('a second run changes nothing', () => {
|
|
112
|
+
withFixture((dir) => {
|
|
113
|
+
ruby(POD_DEPLOYMENT_FLOOR_SOURCE, ['Pods'], dir);
|
|
114
|
+
const once = readFileSync(join(dir, 'Pods', 'Pods.xcodeproj', 'project.pbxproj'), 'utf8');
|
|
115
|
+
expect(ruby(POD_DEPLOYMENT_FLOOR_SOURCE, ['Pods'], dir)).toContain('No pod target is below it');
|
|
116
|
+
expect(readFileSync(join(dir, 'Pods', 'Pods.xcodeproj', 'project.pbxproj'), 'utf8')).toBe(once);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
test('no workspace to read the app from: says so, raises nothing, exits 0', () => {
|
|
120
|
+
withFixture((dir) => {
|
|
121
|
+
rmSync(join(dir, 'App.xcworkspace'), { recursive: true, force: true });
|
|
122
|
+
const before = readFileSync(join(dir, 'Pods', 'Pods.xcodeproj', 'project.pbxproj'), 'utf8');
|
|
123
|
+
expect(ruby(POD_DEPLOYMENT_FLOOR_SOURCE, ['Pods'], dir)).toContain('left as they are');
|
|
124
|
+
expect(readFileSync(join(dir, 'Pods', 'Pods.xcodeproj', 'project.pbxproj'), 'utf8')).toBe(before);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
if (!hasXcodeproj) {
|
|
129
|
+
test.skip('the raise on real projects — this ruby cannot load xcodeproj', () => { });
|
|
130
|
+
}
|
|
131
|
+
describe('cocoapods-install runs the raise after pod install', () => {
|
|
132
|
+
const script = async (inputs = {}) => (await new CocoapodsInstallStepExecutor().execute(inputs, {}, testConfig)).script;
|
|
133
|
+
test('after the pod command, before the step reports done', async () => {
|
|
134
|
+
const s = await script();
|
|
135
|
+
const raise = s.indexOf('cibuild-pod-floor');
|
|
136
|
+
expect(raise).toBeGreaterThan(s.indexOf('$POD_INVOCATION $POD_CMD'));
|
|
137
|
+
expect(raise).toBeLessThan(s.indexOf('✅ CocoaPods'));
|
|
138
|
+
});
|
|
139
|
+
test('carries the Ruby verbatim, in a quoted heredoc', async () => {
|
|
140
|
+
const s = await script();
|
|
141
|
+
expect(s).toContain(`<< 'CIBUILD_POD_FLOOR_EOF'`);
|
|
142
|
+
expect(s).toContain(POD_DEPLOYMENT_FLOOR_SOURCE.trim());
|
|
143
|
+
});
|
|
144
|
+
test('never fails the step', () => {
|
|
145
|
+
const lines = podDeploymentFloorLines().join('\n');
|
|
146
|
+
expect(lines).toContain('|| echo "⚠️ Could not raise pods');
|
|
147
|
+
expect(lines).not.toMatch(/\bexit 1\b/);
|
|
148
|
+
});
|
|
149
|
+
test('the emitted script is valid bash', async () => {
|
|
150
|
+
const dir = mkdtempSync(join(tmpdir(), 'pod-floor-sh-'));
|
|
151
|
+
try {
|
|
152
|
+
const f = join(dir, 's.sh');
|
|
153
|
+
writeFileSync(f, await script({ skip_if_absent: true }));
|
|
154
|
+
expect(() => execFileSync('bash', ['-n', f])).not.toThrow();
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
rmSync(dir, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
test('the emitted lines run end to end: the raise happens through the bash', () => {
|
|
161
|
+
if (!hasXcodeproj)
|
|
162
|
+
return;
|
|
163
|
+
const dir = mkdtempSync(join(tmpdir(), 'pod-floor-e2e-'));
|
|
164
|
+
try {
|
|
165
|
+
ruby(FIXTURE, [dir]);
|
|
166
|
+
const f = join(dir, 'raise.sh');
|
|
167
|
+
writeFileSync(f, ['USE_BUNDLE_EXEC=false', 'BUNDLE_CMD=bundle', ...podDeploymentFloorLines()].join('\n'));
|
|
168
|
+
const out = execFileSync('bash', [f], { cwd: dir, encoding: 'utf8' });
|
|
169
|
+
expect(out).toContain('Raised 1 pod target(s)');
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
rmSync(dir, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
//# sourceMappingURL=cocoapods-deployment-floor.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ios-deps.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ios-deps.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ios-deps.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ios-deps.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,wBAAwB,CAAC;AAMhF,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,gBAAgB;IAChE,yBAAyB,CACvB,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAgNpB;AAMD,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,gBAAgB;IACxD,yBAAyB,CACvB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAyDpB"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { BaseStepExecutor } from './base.js';
|
|
5
5
|
import { refusedFetchHelpers, retryOnRefusedFetch } from './git-fetch-retry.js';
|
|
6
|
+
import { podDeploymentFloorLines } from './cocoapods-deployment-floor.js';
|
|
6
7
|
/**
|
|
7
8
|
* Runs `pod install` or `pod update`.
|
|
8
9
|
* Auto-detects Gemfile and uses `bundle exec pod` when appropriate.
|
|
@@ -210,6 +211,7 @@ export class CocoapodsInstallStepExecutor extends BaseStepExecutor {
|
|
|
210
211
|
command: '$POD_INVOCATION $POD_CMD',
|
|
211
212
|
}));
|
|
212
213
|
commands.push('');
|
|
214
|
+
commands.push(...podDeploymentFloorLines());
|
|
213
215
|
commands.push('echo "✅ CocoaPods ${POD_CMD%% *} completed"');
|
|
214
216
|
const script = this.createBashScriptFromCommands(commands, stepName);
|
|
215
217
|
return this.createScriptStep(script, stepName);
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
import { describe, test, expect } from '@jest/globals';
|
|
30
30
|
import { execFileSync } from 'child_process';
|
|
31
|
-
import { mkdtempSync, realpathSync } from 'fs';
|
|
31
|
+
import { mkdtempSync, realpathSync, symlinkSync } from 'fs';
|
|
32
32
|
import { tmpdir } from 'os';
|
|
33
33
|
import { join } from 'path';
|
|
34
34
|
import { XcodeBuildStepExecutor, XcodeBuildForTestStepExecutor, XcodeBuildForSimulatorStepExecutor, } from './xcode.js';
|
|
@@ -226,6 +226,23 @@ describe('derived data is outside the source tree', () => {
|
|
|
226
226
|
const b = resolve(script, { CIBUILD_SCRATCH: '/scratch', OUTPUT_DIR: '/work/repo/build' });
|
|
227
227
|
expect(a).not.toBe(b);
|
|
228
228
|
});
|
|
229
|
+
// analogcode/Swift-Radio-Pro: LNPopupController's Package.swift lists its
|
|
230
|
+
// header directories with FileManager (real paths, /private/tmp/...) and
|
|
231
|
+
// strips packageBase.path (/tmp/...) by text replacement, so every header
|
|
232
|
+
// search path came out eight characters short and '_LNPopupGlassUtils.h'
|
|
233
|
+
// was not found. On macOS /tmp and TMPDIR's /var are symlinks into
|
|
234
|
+
// /private; derived data has to be named by its real path.
|
|
235
|
+
test('derived data is named by its real path, not through a symlink', async () => {
|
|
236
|
+
const real = realpathSync(mkdtempSync(join(tmpdir(), 'real-')));
|
|
237
|
+
const link = join(realpathSync(mkdtempSync(join(tmpdir(), 'link-'))), 'tmp');
|
|
238
|
+
symlinkSync(real, link);
|
|
239
|
+
const script = await scriptFor(new XcodeBuildStepExecutor(), {});
|
|
240
|
+
const lines = script.split('\n');
|
|
241
|
+
const from = lines.findIndex((l) => l.startsWith('DERIVED_DATA_PATH='));
|
|
242
|
+
const to = lines.findIndex((l) => l.startsWith('echo "Derived data:'));
|
|
243
|
+
const path = execFileSync('bash', ['-c', `set -e\n${lines.slice(from, to).join('\n')}\nprintf '%s' "$DERIVED_DATA_PATH"`], { env: { PATH: process.env.PATH ?? '', TMPDIR: link, OUTPUT_DIR: '/work/repo/build' } }).toString();
|
|
244
|
+
expect(path.startsWith(real + '/')).toBe(true);
|
|
245
|
+
});
|
|
229
246
|
test('the product listing and the xctestrun search follow it', async () => {
|
|
230
247
|
const build = await scriptFor(new XcodeBuildStepExecutor(), {});
|
|
231
248
|
expect(build).toContain('ls -lhR "$DERIVED_DATA_PATH/Build/Products"');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The simulator architecture, chosen at run time.
|
|
3
|
+
*
|
|
4
|
+
* A pipeline pins `ARCHS=arm64` on its simulator builds: a *generic* simulator
|
|
5
|
+
* destination otherwise exports `ARCHS='arm64 x86_64'`, and anything that maps
|
|
6
|
+
* ARCHS onto a second toolchain meets an architecture nothing on the runner
|
|
7
|
+
* builds. But a project can exclude arm64 from the simulator
|
|
8
|
+
* (`EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64`, an Intel-era workaround),
|
|
9
|
+
* and then the pin leaves nothing to build: "None of the architectures in
|
|
10
|
+
* ARCHS (arm64) are valid", and CocoaPods' `[CP] Embed Pods Frameworks` dies
|
|
11
|
+
* on `ARCHS[@]: unbound variable`.
|
|
12
|
+
*
|
|
13
|
+
* Invarn switches to x86_64 at pipeline creation when the exclusion is in the
|
|
14
|
+
* repository (the pbxproj or the Podfile). A pod can also carry it, in its
|
|
15
|
+
* podspec's `user_target_xcconfig`, which CocoaPods writes into the app's
|
|
16
|
+
* `Pods-…debug.xcconfig` — and that exists only after `pod install`
|
|
17
|
+
* (ExistOrLive/GithubClient: WoodPeckeriOS 1.4.3, nightly-baseline issue 54).
|
|
18
|
+
* So the step asks Xcode, right before it builds, for the effective settings:
|
|
19
|
+
* `-showBuildSettings` reads the pbxproj, every xcconfig and the pods at once.
|
|
20
|
+
*
|
|
21
|
+
* Only an `ARCHS=arm64` pin is checked. An `ARCHS=x86_64` chosen at creation
|
|
22
|
+
* is left as it is, and options without a pin have nothing to decide.
|
|
23
|
+
*/
|
|
24
|
+
/** The variable the build line reads its simulator architecture from. */
|
|
25
|
+
export declare const SIMULATOR_ARCHS_VAR = "CIBUILD_SIMULATOR_ARCHS";
|
|
26
|
+
/** Whether `xcodebuild_options` pins the simulator build to arm64. */
|
|
27
|
+
export declare function pinsSimulatorArm64(xcodebuildOptions: string): boolean;
|
|
28
|
+
/** The options with the arm64 pin replaced by the run-time choice. */
|
|
29
|
+
export declare function withRuntimeSimulatorArchs(xcodebuildOptions: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Reads `xcodebuild -showBuildSettings -json` on stdin and prints one line
|
|
32
|
+
* naming the target that excludes arm64, or nothing. The application target
|
|
33
|
+
* decides when the scheme lists one; a framework the scheme also lists is not
|
|
34
|
+
* what is being built for the simulator. Output it cannot read is no
|
|
35
|
+
* evidence: it prints nothing and exits 0, and the build keeps arm64.
|
|
36
|
+
*/
|
|
37
|
+
export declare const ARM64_EXCLUSION_READER_SOURCE: string;
|
|
38
|
+
/**
|
|
39
|
+
* The lines that set `$CIBUILD_SIMULATOR_ARCHS`: arm64, or x86_64 when the
|
|
40
|
+
* project's effective simulator settings exclude arm64, saying so in the log.
|
|
41
|
+
* They expect `$PROJECT_TYPE` and `$DERIVED_DATA_PATH` to be set, and go after
|
|
42
|
+
* package resolution, so the settings are read from the graph the build uses.
|
|
43
|
+
*/
|
|
44
|
+
export declare function simulatorArchsLines(opts: {
|
|
45
|
+
/** Already escaped for a single-quoted bash string. */
|
|
46
|
+
projectPath: string;
|
|
47
|
+
scheme: string;
|
|
48
|
+
configuration: string;
|
|
49
|
+
destination: string;
|
|
50
|
+
/** Pass `-xcconfig "$XCCONFIG_FILE"` too, as the build does. */
|
|
51
|
+
xcconfig: boolean;
|
|
52
|
+
}): string[];
|
|
53
|
+
//# sourceMappingURL=xcode-simulator-archs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode-simulator-archs.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode-simulator-archs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAE7D,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAErE;AAED,sEAAsE;AACtE,wBAAgB,yBAAyB,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAqB3C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,EAAE,CAyBX"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The simulator architecture, chosen at run time.
|
|
3
|
+
*
|
|
4
|
+
* A pipeline pins `ARCHS=arm64` on its simulator builds: a *generic* simulator
|
|
5
|
+
* destination otherwise exports `ARCHS='arm64 x86_64'`, and anything that maps
|
|
6
|
+
* ARCHS onto a second toolchain meets an architecture nothing on the runner
|
|
7
|
+
* builds. But a project can exclude arm64 from the simulator
|
|
8
|
+
* (`EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64`, an Intel-era workaround),
|
|
9
|
+
* and then the pin leaves nothing to build: "None of the architectures in
|
|
10
|
+
* ARCHS (arm64) are valid", and CocoaPods' `[CP] Embed Pods Frameworks` dies
|
|
11
|
+
* on `ARCHS[@]: unbound variable`.
|
|
12
|
+
*
|
|
13
|
+
* Invarn switches to x86_64 at pipeline creation when the exclusion is in the
|
|
14
|
+
* repository (the pbxproj or the Podfile). A pod can also carry it, in its
|
|
15
|
+
* podspec's `user_target_xcconfig`, which CocoaPods writes into the app's
|
|
16
|
+
* `Pods-…debug.xcconfig` — and that exists only after `pod install`
|
|
17
|
+
* (ExistOrLive/GithubClient: WoodPeckeriOS 1.4.3, nightly-baseline issue 54).
|
|
18
|
+
* So the step asks Xcode, right before it builds, for the effective settings:
|
|
19
|
+
* `-showBuildSettings` reads the pbxproj, every xcconfig and the pods at once.
|
|
20
|
+
*
|
|
21
|
+
* Only an `ARCHS=arm64` pin is checked. An `ARCHS=x86_64` chosen at creation
|
|
22
|
+
* is left as it is, and options without a pin have nothing to decide.
|
|
23
|
+
*/
|
|
24
|
+
const ARM64_PIN = /(^|\s)ARCHS=arm64(?=\s|$)/;
|
|
25
|
+
/** The variable the build line reads its simulator architecture from. */
|
|
26
|
+
export const SIMULATOR_ARCHS_VAR = 'CIBUILD_SIMULATOR_ARCHS';
|
|
27
|
+
/** Whether `xcodebuild_options` pins the simulator build to arm64. */
|
|
28
|
+
export function pinsSimulatorArm64(xcodebuildOptions) {
|
|
29
|
+
return ARM64_PIN.test(xcodebuildOptions);
|
|
30
|
+
}
|
|
31
|
+
/** The options with the arm64 pin replaced by the run-time choice. */
|
|
32
|
+
export function withRuntimeSimulatorArchs(xcodebuildOptions) {
|
|
33
|
+
return xcodebuildOptions.replace(ARM64_PIN, (_m, lead) => `${lead}ARCHS="$${SIMULATOR_ARCHS_VAR}"`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reads `xcodebuild -showBuildSettings -json` on stdin and prints one line
|
|
37
|
+
* naming the target that excludes arm64, or nothing. The application target
|
|
38
|
+
* decides when the scheme lists one; a framework the scheme also lists is not
|
|
39
|
+
* what is being built for the simulator. Output it cannot read is no
|
|
40
|
+
* evidence: it prints nothing and exits 0, and the build keeps arm64.
|
|
41
|
+
*/
|
|
42
|
+
export const ARM64_EXCLUSION_READER_SOURCE = String.raw `
|
|
43
|
+
var input = '';
|
|
44
|
+
process.stdin.setEncoding('utf8');
|
|
45
|
+
process.stdin.on('data', function (d) { input += d; });
|
|
46
|
+
process.stdin.on('end', function () {
|
|
47
|
+
var entries;
|
|
48
|
+
try { entries = JSON.parse(input); } catch (err) { return; }
|
|
49
|
+
if (!Array.isArray(entries)) return;
|
|
50
|
+
var apps = entries.filter(function (e) {
|
|
51
|
+
return e && e.buildSettings && e.buildSettings.PRODUCT_TYPE === 'com.apple.product-type.application';
|
|
52
|
+
});
|
|
53
|
+
var judged = apps.length > 0 ? apps : entries;
|
|
54
|
+
for (var i = 0; i < judged.length; i++) {
|
|
55
|
+
var e = judged[i];
|
|
56
|
+
var excluded = String((e && e.buildSettings && e.buildSettings.EXCLUDED_ARCHS) || '').trim();
|
|
57
|
+
if (excluded.split(/\s+/).indexOf('arm64') >= 0) {
|
|
58
|
+
process.stdout.write('target ' + e.target + ' sets EXCLUDED_ARCHS = ' + excluded + '\n');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
`;
|
|
64
|
+
/**
|
|
65
|
+
* The lines that set `$CIBUILD_SIMULATOR_ARCHS`: arm64, or x86_64 when the
|
|
66
|
+
* project's effective simulator settings exclude arm64, saying so in the log.
|
|
67
|
+
* They expect `$PROJECT_TYPE` and `$DERIVED_DATA_PATH` to be set, and go after
|
|
68
|
+
* package resolution, so the settings are read from the graph the build uses.
|
|
69
|
+
*/
|
|
70
|
+
export function simulatorArchsLines(opts) {
|
|
71
|
+
let ask = 'xcodebuild -showBuildSettings -json';
|
|
72
|
+
ask += ` "$PROJECT_TYPE" '${opts.projectPath}'`;
|
|
73
|
+
ask += ` -scheme '${opts.scheme}'`;
|
|
74
|
+
if (opts.configuration)
|
|
75
|
+
ask += ` -configuration '${opts.configuration}'`;
|
|
76
|
+
ask += ` -destination '${opts.destination}'`;
|
|
77
|
+
ask += ' -derivedDataPath "$DERIVED_DATA_PATH"';
|
|
78
|
+
if (opts.xcconfig)
|
|
79
|
+
ask += ' -xcconfig "$XCCONFIG_FILE"';
|
|
80
|
+
return [
|
|
81
|
+
'# The simulator architecture, read after pod install: a pod can exclude',
|
|
82
|
+
'# arm64 through its user_target_xcconfig, which no file in the repository',
|
|
83
|
+
'# says until CocoaPods has run. See xcode-simulator-archs.ts.',
|
|
84
|
+
`${SIMULATOR_ARCHS_VAR}=arm64`,
|
|
85
|
+
'ARCHS_READER="$(mktemp -t cibuild-sim-archs).cjs"',
|
|
86
|
+
`cat > "$ARCHS_READER" << 'CIBUILD_SIM_ARCHS_EOF'`,
|
|
87
|
+
ARM64_EXCLUSION_READER_SOURCE.trim(),
|
|
88
|
+
'CIBUILD_SIM_ARCHS_EOF',
|
|
89
|
+
`ARM64_EXCLUDED_BY=$(${ask} 2>/dev/null | node "$ARCHS_READER" 2>/dev/null || true)`,
|
|
90
|
+
'rm -f "$ARCHS_READER"',
|
|
91
|
+
'if [ -n "$ARM64_EXCLUDED_BY" ]; then',
|
|
92
|
+
` ${SIMULATOR_ARCHS_VAR}=x86_64`,
|
|
93
|
+
' echo "Building the simulator app as x86_64, not arm64: $ARM64_EXCLUDED_BY in the project\'s effective simulator settings (after pod install)"',
|
|
94
|
+
'fi',
|
|
95
|
+
'',
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=xcode-simulator-archs.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simulator build pinned to arm64, on a project whose effective settings
|
|
3
|
+
* exclude arm64 from the simulator, builds x86_64 instead — decided at run
|
|
4
|
+
* time, after `pod install`, from what Xcode itself reports.
|
|
5
|
+
*
|
|
6
|
+
* The witness (nightly-baseline issue 54): ExistOrLive/GithubClient @ 7969212a.
|
|
7
|
+
* Its pod WoodPeckeriOS 1.4.3 ships `user_target_xcconfig:
|
|
8
|
+
* { "EXCLUDED_ARCHS[sdk=iphonesimulator*]": "arm64" }`, which CocoaPods writes
|
|
9
|
+
* into the app's `Pods-…debug.xcconfig`. The pipeline pinned `ARCHS=arm64`, so
|
|
10
|
+
* nothing was left to build and `[CP] Embed Pods Frameworks` died on
|
|
11
|
+
* `ARCHS[@]: unbound variable` (bld_b91e230368d6505e97ec9b75). Nothing in the
|
|
12
|
+
* repository says so before `pod install` has run.
|
|
13
|
+
*
|
|
14
|
+
* Measured on a clone, Xcode 26.4, 2026-10-01: after `pod install`,
|
|
15
|
+
* `xcodebuild -showBuildSettings -json … -destination 'generic/platform=iOS
|
|
16
|
+
* Simulator'` reported, for target ZLGitHubClient
|
|
17
|
+
* (com.apple.product-type.application), `EXCLUDED_ARCHS = "arm64"`, in 3 s;
|
|
18
|
+
* and `ARCHS=x86_64` compiled the app's sources.
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=xcode-simulator-archs.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode-simulator-archs.test.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode-simulator-archs.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
|