Skip to content

Commit 2d80285

Browse files
iinozemtsevCommit Queue
authored andcommitted
SDK Cache fixes for dartdev cross compilation
- Use `signed` stage only for executables (dartaotruntime is not signed) - Ensure user-executable bit only for executables - Fix Windows path issue (#60462) Change-Id: I012c6df34174e292979610dabf1e9a5f486ef39e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/420101 Reviewed-by: Tess Strickland <[email protected]> Commit-Queue: Ivan Inozemtsev <[email protected]>
1 parent dced5e0 commit 2d80285

File tree

2 files changed

+154
-68
lines changed

2 files changed

+154
-68
lines changed

pkg/dartdev/lib/src/sdk_cache.dart

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:file/file.dart';
1010
import 'package:file/local.dart';
1111
import 'package:http/http.dart' as http;
1212
import 'package:native_assets_cli/code_assets_builder.dart' show OS, Target;
13-
import 'package:path/path.dart' as path;
1413

1514
/// S_IXUSR bit from POSIX sys/stat.h.
1615
///
@@ -23,18 +22,13 @@ const sIxusr = 0x40;
2322
class ArchiveFolder {
2423
final String version;
2524
final String revision;
26-
2725
final Channel channel;
28-
final Stage stage;
2926

30-
Uri fileUri(String path) => SdkCache.archiveUri(
31-
channel: channel, stage: stage, version: 'hash/$revision', path: path);
27+
Uri fileUri(String path, {required Stage stage}) => SdkCache.archiveUri(
28+
channel: channel, version: 'hash/$revision', stage: stage, path: path);
3229

3330
ArchiveFolder(
34-
{required this.version,
35-
required this.revision,
36-
required this.channel,
37-
required this.stage});
31+
{required this.version, required this.revision, required this.channel});
3832
}
3933

4034
/// Cache for retrieving artifacts that are not shipped with the Dart SDK.
@@ -85,14 +79,8 @@ class SdkCache {
8579
throw ArgumentError('Unsupported channel: "$channelName".');
8680
}
8781

88-
// Require signed artifacts on macOS past main channel (main channel
89-
// releases aren't signed).
90-
final stage = host.os == OS.macOS && channel != Channel.main
91-
? Stage.signed
92-
: Stage.raw;
93-
94-
final folderFromArgs = ArchiveFolder(
95-
version: version, revision: revision, channel: channel, stage: stage);
82+
final folderFromArgs =
83+
ArchiveFolder(version: version, revision: revision, channel: channel);
9684
if (channel != Channel.main) {
9785
// Past main channel, we always assume that given version and revision
9886
// must exist on the server.
@@ -104,19 +92,23 @@ class SdkCache {
10492
return folderFromArgs;
10593
}
10694

95+
// Require signed artifacts on macOS past main channel (main channel
96+
// releases aren't signed).
97+
final stage = host.os == OS.macOS && channel != Channel.main
98+
? Stage.signed
99+
: Stage.raw;
100+
107101
// On the main channel, on contrary, we do not trust the revision, because
108102
// it can be empty (if Dart SDK is built with RBE), or be at the local
109103
// commit revision, which does not exist on storage.
110104
if (revision.isNotEmpty) {
111105
// Check that the given revision exists.
112-
var exists = await _exists(folderFromArgs.fileUri('VERSION'));
106+
var exists =
107+
await _exists(folderFromArgs.fileUri('VERSION', stage: stage));
113108

114109
if (exists) {
115110
return ArchiveFolder(
116-
version: version,
117-
revision: revision,
118-
channel: channel,
119-
stage: stage);
111+
version: version, revision: revision, channel: channel);
120112
} else {
121113
if (verbose) {
122114
_stderr.writeln('Cannot find revision $revision in an archive.');
@@ -132,7 +124,7 @@ class SdkCache {
132124
_stderr.writeln('Using revision $revision.');
133125
}
134126
return ArchiveFolder(
135-
version: version, revision: revision, channel: channel, stage: stage);
127+
version: version, revision: revision, channel: channel);
136128
}
137129

138130
void _ensureExecutable(File destinationFile, OS hostOS) {
@@ -168,7 +160,8 @@ class SdkCache {
168160
archiveFolder: archiveFolder,
169161
host: host,
170162
target: target,
171-
basename: basename);
163+
basename: basename,
164+
isExecutable: true);
172165
}
173166

174167
Future<String> ensureDartAotRuntime({
@@ -178,29 +171,36 @@ class SdkCache {
178171
}) {
179172
host ??= Target.current;
180173
return ensureArtifact(
181-
archiveFolder: archiveFolder,
182-
basename: 'dartaotruntime_$target',
183-
target: target,
184-
host: host,
185-
);
174+
archiveFolder: archiveFolder,
175+
basename: 'dartaotruntime_$target',
176+
target: target,
177+
host: host,
178+
isExecutable: false);
186179
}
187180

188181
Future<String> ensureArtifact({
189182
required ArchiveFolder archiveFolder,
190183
required String basename,
191184
required Target target,
192185
required Target host,
186+
required bool isExecutable,
193187
}) async {
194188
// Calculate the local path.
195189
var localFile =
196-
fs.file(path.join(directory.path, archiveFolder.version, basename));
190+
directory.childDirectory(archiveFolder.version).childFile(basename);
197191
if (localFile.existsSync()) {
198-
_ensureExecutable(localFile, host.os);
192+
if (isExecutable) {
193+
_ensureExecutable(localFile, host.os);
194+
}
199195
return localFile.path;
200196
}
201197

202198
localFile.parent.createSync(recursive: true);
203-
final uri = archiveFolder.fileUri('sdk/$basename');
199+
final uri = archiveFolder.fileUri('sdk/$basename',
200+
stage: resolveStage(
201+
channel: archiveFolder.channel,
202+
isExecutable: isExecutable,
203+
hostOS: host.os));
204204

205205
try {
206206
localFile.writeAsBytesSync(await _download(uri));
@@ -209,7 +209,10 @@ class SdkCache {
209209
_stderr.writeln('If the problem persists, try downloading it manually.');
210210
rethrow;
211211
}
212-
_ensureExecutable(localFile, host.os);
212+
213+
if (isExecutable) {
214+
_ensureExecutable(localFile, host.os);
215+
}
213216
return localFile.path;
214217
}
215218

@@ -246,6 +249,17 @@ class SdkCache {
246249
return response.bodyBytes;
247250
}
248251

252+
static Stage resolveStage(
253+
{required Channel channel,
254+
required bool isExecutable,
255+
required OS hostOS}) {
256+
if (channel == Channel.main || !isExecutable) {
257+
return Stage.raw;
258+
}
259+
260+
return hostOS == OS.macOS ? Stage.signed : Stage.raw;
261+
}
262+
249263
static Uri archiveUri(
250264
{required Channel channel,
251265
required Stage stage,

pkg/dartdev/test/sdk_cache_test.dart

Lines changed: 107 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:file/file.dart';
99
import 'package:file/memory.dart';
1010
import 'package:http/http.dart' as http;
1111
import 'package:http/testing.dart' as http;
12-
import 'package:native_assets_cli/code_assets_builder.dart' show Target;
12+
import 'package:native_assets_cli/code_assets_builder.dart' show Target, OS;
1313
import 'package:test/test.dart';
1414

1515
const dartArchiveUri = 'https://storage.googleapis.com/dart-archive';
@@ -22,13 +22,17 @@ void main() {
2222
late Map<String, io.ProcessResult> chmodRuns;
2323

2424
setUp(() {
25-
fs = MemoryFileSystem();
25+
// Make sure we support both path separators.
26+
fs = MemoryFileSystem(
27+
style: io.Platform.isWindows
28+
? FileSystemStyle.windows
29+
: FileSystemStyle.posix);
2630
stderr = StringBuffer();
2731
expectedRequests = <String, http.Response>{};
2832
chmodRuns = <String, io.ProcessResult>{};
2933

3034
cache = SdkCache(
31-
directory: '/tmp/cache',
35+
directory: fs.directory(Uri.file('/tmp/cache')).path,
3236
stderr: stderr,
3337
verbose: true,
3438
fs: fs,
@@ -42,6 +46,29 @@ void main() {
4246
chmod: (path) => chmodRuns[path]!);
4347
});
4448

49+
group('resolveStage', () {
50+
test('Uses signed on macOS dev for executables', () {
51+
expect(
52+
SdkCache.resolveStage(
53+
channel: Channel.dev, isExecutable: true, hostOS: OS.macOS),
54+
Stage.signed);
55+
});
56+
57+
test('Uses raw on macOS main for executables', () {
58+
expect(
59+
SdkCache.resolveStage(
60+
channel: Channel.main, isExecutable: true, hostOS: OS.macOS),
61+
Stage.raw);
62+
});
63+
64+
test('Uses raw on macOS stable for non-executables', () {
65+
expect(
66+
SdkCache.resolveStage(
67+
channel: Channel.stable, isExecutable: false, hostOS: OS.macOS),
68+
Stage.raw);
69+
});
70+
});
71+
4572
group('resolveVersion', () {
4673
test('Resolves release version', () async {
4774
final version = '3.4.4';
@@ -53,28 +80,11 @@ void main() {
5380
host: Target.linuxArm64);
5481
expect(folder.version, version);
5582
expect(folder.revision, revision);
56-
expect(folder.stage, Stage.raw);
5783
expect(folder.channel, Channel.stable);
58-
expect(folder.fileUri('VERSION').toString(),
84+
expect(folder.fileUri('VERSION', stage: Stage.raw).toString(),
5985
'$dartArchiveUri/channels/stable/raw/hash/$revision/VERSION');
6086
});
6187

62-
test('Uses signed binaries on macOS', () async {
63-
final version = '3.8.0-171.2.beta';
64-
final revision = '54cec4d7d36e7a5066770287998f425606a2f983';
65-
final folder = await cache.resolveVersion(
66-
version: version,
67-
revision: revision,
68-
channelName: 'beta',
69-
host: Target.macOSArm64);
70-
expect(folder.version, version);
71-
expect(folder.revision, revision);
72-
expect(folder.stage, Stage.signed);
73-
expect(folder.channel, Channel.beta);
74-
expect(folder.fileUri('').toString(),
75-
'$dartArchiveUri/channels/beta/signed/hash/$revision/');
76-
});
77-
7888
test('Falls back to the latest on empty main revision', () async {
7989
final version = '3.8.0';
8090
final revision = '';
@@ -95,7 +105,6 @@ void main() {
95105
host: Target.macOSArm64);
96106
expect(folder.version, latestVersion);
97107
expect(folder.revision, latestRevision);
98-
expect(folder.stage, Stage.raw);
99108
expect(folder.channel, Channel.main);
100109
});
101110

@@ -124,7 +133,6 @@ void main() {
124133
host: Target.macOSArm64);
125134
expect(folder.version, latestVersion);
126135
expect(folder.revision, latestRevision);
127-
expect(folder.stage, Stage.raw);
128136
expect(folder.channel, Channel.main);
129137
});
130138

@@ -147,31 +155,49 @@ void main() {
147155
final version = '3.4.4';
148156
final revision = '60465149414572c8ca189d8f65fdb39795c4b97d';
149157

150-
final genSnapshotFile = fs
151-
.file('/tmp/cache/$version/gen_snapshot_windows_arm64_linux_x64.exe');
158+
final genSnapshotFile = fs.file(Uri.file(
159+
'/tmp/cache/$version/gen_snapshot_windows_arm64_linux_x64.exe'));
152160
genSnapshotFile.createSync(exclusive: true, recursive: true);
153161

154162
final path = await cache.ensureGenSnapshot(
155163
archiveFolder: ArchiveFolder(
156-
channel: Channel.stable,
157-
stage: Stage.raw,
158-
version: version,
159-
revision: revision),
164+
channel: Channel.stable, version: version, revision: revision),
160165
host: Target.windowsArm64,
161166
target: Target.linuxX64);
162167
expect(path, genSnapshotFile.path);
163168
});
164169

165-
test('Downloads', () async {
170+
test('Downloads signed gen_snapshot on macOS beta', () async {
166171
final version = '3.8.0-171.2.beta';
167172
final revision = '54cec4d7d36e7a5066770287998f425606a2f983';
168173

169174
final archiveFolder = ArchiveFolder(
170-
channel: Channel.beta,
171-
stage: Stage.signed,
172-
version: version,
173-
revision: revision);
175+
channel: Channel.beta, version: version, revision: revision);
174176
expectedRequests['GET $dartArchiveUri/channels/beta/signed/hash/'
177+
'$revision/sdk/gen_snapshot_macos_arm64_linux_x64'] =
178+
http.Response('i am gen_snapshot', io.HttpStatus.ok);
179+
180+
final path = await cache.ensureGenSnapshot(
181+
archiveFolder: archiveFolder,
182+
host: Target.macOSArm64,
183+
target: Target.linuxX64);
184+
185+
expect(
186+
path,
187+
fs
188+
.file(Uri.file(
189+
'/tmp/cache/$version/gen_snapshot_macos_arm64_linux_x64'))
190+
.path);
191+
expect(fs.file(path).readAsStringSync(), 'i am gen_snapshot');
192+
});
193+
194+
test('Downloads raw dartaotruntime on macOS beta', () async {
195+
final version = '3.8.0-171.2.beta';
196+
final revision = '54cec4d7d36e7a5066770287998f425606a2f983';
197+
198+
final archiveFolder = ArchiveFolder(
199+
channel: Channel.beta, version: version, revision: revision);
200+
expectedRequests['GET $dartArchiveUri/channels/beta/raw/hash/'
175201
'$revision/sdk/dartaotruntime_linux_x64'] =
176202
http.Response('i am dartaotruntime', io.HttpStatus.ok);
177203

@@ -180,7 +206,53 @@ void main() {
180206
host: Target.macOSArm64,
181207
target: Target.linuxX64);
182208

183-
expect(path, '/tmp/cache/$version/dartaotruntime_linux_x64');
209+
expect(
210+
path,
211+
fs
212+
.file(Uri.file('/tmp/cache/$version/dartaotruntime_linux_x64'))
213+
.path);
214+
expect(fs.file(path).readAsStringSync(), 'i am dartaotruntime');
215+
});
216+
217+
test('Downloads gen_snapshot.exe on Windows stable', () async {
218+
final version = '3.7.2';
219+
final channel = Channel.stable;
220+
final revision = '9594995093f642957b780603c6435d9e7a61b923';
221+
final binary = 'gen_snapshot_windows_x64_linux_x64.exe';
222+
223+
final archiveFolder =
224+
ArchiveFolder(channel: channel, version: version, revision: revision);
225+
expectedRequests['GET $dartArchiveUri/channels/stable/raw/hash/'
226+
'$revision/sdk/$binary'] =
227+
http.Response('i am gen_snapshot', io.HttpStatus.ok);
228+
229+
final path = await cache.ensureGenSnapshot(
230+
archiveFolder: archiveFolder,
231+
host: Target.windowsX64,
232+
target: Target.linuxX64);
233+
234+
expect(path, fs.file(Uri.file('/tmp/cache/$version/$binary')).path);
235+
expect(fs.file(path).readAsStringSync(), 'i am gen_snapshot');
236+
});
237+
238+
test('Downloads dartaotruntime on Windows stable', () async {
239+
final version = '3.7.2';
240+
final channel = Channel.stable;
241+
final revision = '9594995093f642957b780603c6435d9e7a61b923';
242+
final binary = 'dartaotruntime_linux_x64';
243+
244+
final archiveFolder =
245+
ArchiveFolder(channel: channel, version: version, revision: revision);
246+
expectedRequests['GET $dartArchiveUri/channels/stable/raw/hash/'
247+
'$revision/sdk/$binary'] =
248+
http.Response('i am dartaotruntime', io.HttpStatus.ok);
249+
250+
final path = await cache.ensureDartAotRuntime(
251+
archiveFolder: archiveFolder,
252+
host: Target.windowsX64,
253+
target: Target.linuxX64);
254+
255+
expect(path, fs.file(Uri.file('/tmp/cache/$version/$binary')).path);
184256
expect(fs.file(path).readAsStringSync(), 'i am dartaotruntime');
185257
});
186258
});

0 commit comments

Comments
 (0)