Skip to content

Commit 820b5f3

Browse files
authored
Fix mode bits when importing an old archive in test profile. (#8130)
1 parent 36e7106 commit 820b5f3

File tree

4 files changed

+50
-13
lines changed

4 files changed

+50
-13
lines changed

app/lib/shared/utils.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:collection';
99
import 'dart:convert';
1010
import 'dart:io';
1111
import 'dart:math';
12+
import 'dart:typed_data';
1213

1314
import 'package:appengine/appengine.dart';
1415
import 'package:intl/intl.dart';
@@ -300,3 +301,14 @@ extension StringExt on String {
300301
return v.isEmpty ? null : v;
301302
}
302303
}
304+
305+
extension ByteFolderExt on Stream<List<int>> {
306+
Future<Uint8List> foldBytes() async {
307+
final contents = await toList();
308+
final buffer = BytesBuilder(copy: false);
309+
for (final chunk in contents) {
310+
buffer.add(chunk);
311+
}
312+
return buffer.toBytes();
313+
}
314+
}

app/lib/tool/test_profile/importer.dart

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44

55
// ignore_for_file: invalid_use_of_visible_for_testing_member
66

7+
import 'dart:io';
8+
79
import 'package:_pub_shared/data/admin_api.dart';
810
import 'package:_pub_shared/data/package_api.dart';
911
import 'package:_pub_shared/search/tags.dart';
1012
import 'package:meta/meta.dart';
11-
import 'package:pub_dev/account/auth_provider.dart';
12-
import 'package:pub_dev/fake/backend/fake_auth_provider.dart';
13-
import 'package:pub_dev/frontend/handlers/pubapi.client.dart';
14-
import 'package:pub_dev/service/async_queue/async_queue.dart';
15-
import 'package:pub_dev/shared/configuration.dart';
16-
13+
import 'package:tar/tar.dart';
14+
15+
import '../../account/auth_provider.dart';
16+
import '../../fake/backend/fake_auth_provider.dart';
17+
import '../../frontend/handlers/pubapi.client.dart';
18+
import '../../service/async_queue/async_queue.dart';
19+
import '../../shared/configuration.dart';
20+
import '../../shared/utils.dart';
1721
import '../utils/pub_api_client.dart';
1822
import 'import_source.dart';
1923
import 'models.dart';
@@ -86,8 +90,9 @@ Future<void> importProfile({
8690
uploaderEmails[rv.version.hashCode.abs() % uploaderEmails.length];
8791
lastActiveUploaderEmails[rv.package] = uploaderEmail;
8892

89-
final bytes = pendingBytes['${rv.package}/${rv.version}'] ??
93+
var bytes = pendingBytes['${rv.package}/${rv.version}'] ??
9094
await source.getArchiveBytes(rv.package, rv.version);
95+
bytes = await _mayCleanupTarModeBits(bytes);
9196
try {
9297
await withHttpPubApiClient(
9398
bearerToken: createFakeAuthTokenForEmail(uploaderEmail,
@@ -216,3 +221,24 @@ List<String> _potentialActiveEmails(TestProfile profile, String packageName) {
216221
.members;
217222
return members.map((m) => m.email).toList();
218223
}
224+
225+
/// Old archives may contain mode bits that are not supported with the current
226+
/// upload checks. This method reads the archive and checks for the mode bits.
227+
/// When the archive bits are not supported, it returns a new archive with the
228+
/// bits corrected.
229+
Future<List<int>> _mayCleanupTarModeBits(List<int> bytes) async {
230+
final archiveBuilder = ArchiveBuilder();
231+
final tarReader =
232+
TarReader(Stream.fromIterable([bytes]).transform(gzip.decoder));
233+
var needsUpdate = false;
234+
while (await tarReader.moveNext()) {
235+
final current = tarReader.current;
236+
if (current.header.mode != 420) {
237+
// 644₈
238+
needsUpdate = true;
239+
}
240+
archiveBuilder.addFileBytes(
241+
current.name, await current.contents.foldBytes());
242+
}
243+
return needsUpdate ? archiveBuilder.toTarGzBytes() : bytes;
244+
}

app/test/package/screenshots_test.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:pub_dev/package/screenshots/backend.dart';
6+
import 'package:pub_dev/shared/utils.dart';
67
import 'package:test/test.dart';
78

89
import '../shared/test_services.dart';
@@ -20,9 +21,7 @@ void main() {
2021
1);
2122

2223
expect(
23-
await imageStorage.bucket
24-
.read('new_pkg/1.2.3/image.svg')
25-
.fold<List<int>>(<int>[], (buffer, data) => buffer..addAll(data)),
24+
await imageStorage.bucket.read('new_pkg/1.2.3/image.svg').foldBytes(),
2625
[1]);
2726
});
2827

app/test/tool/test_profile/importer_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void main() {
2323
packages: [
2424
TestPackage(
2525
name: 'retry',
26-
versions: [TestVersion(version: '3.1.1')],
26+
versions: [TestVersion(version: '3.1.0')],
2727
publisher: 'example.com',
2828
)
2929
],
@@ -37,10 +37,10 @@ void main() {
3737
final packages = await dbService.query<Package>().run().toList();
3838
expect(packages.single.name, 'retry');
3939
expect(packages.single.publisherId, 'example.com');
40-
expect(packages.single.latestVersion, '3.1.1');
40+
expect(packages.single.latestVersion, '3.1.0');
4141

4242
final versions = await dbService.query<PackageVersion>().run().toList();
43-
expect(versions.single.version, '3.1.1');
43+
expect(versions.single.version, '3.1.0');
4444
expect(versions.single.uploader, users.single.userId);
4545

4646
final publishers = await dbService.query<Publisher>().run().toList();

0 commit comments

Comments
 (0)