|
4 | 4 |
|
5 | 5 | // ignore_for_file: invalid_use_of_visible_for_testing_member |
6 | 6 |
|
| 7 | +import 'dart:io'; |
| 8 | + |
7 | 9 | import 'package:_pub_shared/data/admin_api.dart'; |
8 | 10 | import 'package:_pub_shared/data/package_api.dart'; |
9 | 11 | import 'package:_pub_shared/search/tags.dart'; |
10 | 12 | 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'; |
17 | 21 | import '../utils/pub_api_client.dart'; |
18 | 22 | import 'import_source.dart'; |
19 | 23 | import 'models.dart'; |
@@ -86,8 +90,9 @@ Future<void> importProfile({ |
86 | 90 | uploaderEmails[rv.version.hashCode.abs() % uploaderEmails.length]; |
87 | 91 | lastActiveUploaderEmails[rv.package] = uploaderEmail; |
88 | 92 |
|
89 | | - final bytes = pendingBytes['${rv.package}/${rv.version}'] ?? |
| 93 | + var bytes = pendingBytes['${rv.package}/${rv.version}'] ?? |
90 | 94 | await source.getArchiveBytes(rv.package, rv.version); |
| 95 | + bytes = await _mayCleanupTarModeBits(bytes); |
91 | 96 | try { |
92 | 97 | await withHttpPubApiClient( |
93 | 98 | bearerToken: createFakeAuthTokenForEmail(uploaderEmail, |
@@ -216,3 +221,24 @@ List<String> _potentialActiveEmails(TestProfile profile, String packageName) { |
216 | 221 | .members; |
217 | 222 | return members.map((m) => m.email).toList(); |
218 | 223 | } |
| 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 | +} |
0 commit comments