use Expand-Archive and Compress-Archive in windows os utils (#58390)
Work towards removal of package:archive and ideally more stable unzipping of artifacts. These commands are available in Powershell 5+, which we already require for windows.
This commit is contained in:
parent
eae77804fe
commit
bbe18f7580
@ -291,7 +291,15 @@ class _WindowsUtils extends OperatingSystemUtils {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
platform: platform,
|
platform: platform,
|
||||||
processManager: processManager,
|
processManager: processManager,
|
||||||
);
|
) {
|
||||||
|
if (processManager.canRun('pwsh.exe')) {
|
||||||
|
_activePowershell = 'pwsh.exe';
|
||||||
|
} else {
|
||||||
|
_activePowershell = 'PowerShell.exe';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _activePowershell;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void makeExecutable(File file) {}
|
void makeExecutable(File file) {}
|
||||||
@ -315,36 +323,30 @@ class _WindowsUtils extends OperatingSystemUtils {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void zip(Directory data, File zipFile) {
|
void zip(Directory data, File zipFile) {
|
||||||
final Archive archive = Archive();
|
final RunResult result = _processUtils.runSync(<String>[
|
||||||
for (final FileSystemEntity entity in data.listSync(recursive: true)) {
|
_activePowershell,
|
||||||
if (entity is! File) {
|
'-command',
|
||||||
continue;
|
'"Compress-Archive ${data.path} -DestinationPath ${zipFile.path}"',
|
||||||
}
|
]);
|
||||||
final File file = entity as File;
|
if (result.stderr.isNotEmpty) {
|
||||||
final String path = file.fileSystem.path.relative(file.path, from: data.path);
|
throw ProcessException(_activePowershell, <String>['Compress-Archive'], result.stderr);
|
||||||
final List<int> bytes = file.readAsBytesSync();
|
|
||||||
archive.addFile(ArchiveFile(path, bytes.length, bytes));
|
|
||||||
}
|
}
|
||||||
zipFile.writeAsBytesSync(ZipEncoder().encode(archive), flush: true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void unzip(File file, Directory targetDirectory) {
|
void unzip(File file, Directory targetDirectory) {
|
||||||
final Archive archive = ZipDecoder().decodeBytes(file.readAsBytesSync());
|
final RunResult result = _processUtils.runSync(<String>[
|
||||||
_unpackArchive(archive, targetDirectory);
|
_activePowershell,
|
||||||
|
'-command',
|
||||||
|
'"Expand-Archive ${file.path} -DestinationPath ${targetDirectory.path}"',
|
||||||
|
], throwOnError: true);
|
||||||
|
if (result.stderr.isNotEmpty) {
|
||||||
|
throw ProcessException(_activePowershell, <String>['Expand-Archive'], result.stderr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool verifyZip(File zipFile) {
|
bool verifyZip(File zipFile) => true;
|
||||||
try {
|
|
||||||
ZipDecoder().decodeBytes(zipFile.readAsBytesSync(), verify: true);
|
|
||||||
} on FileSystemException catch (_) {
|
|
||||||
return false;
|
|
||||||
} on ArchiveException catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void unpack(File gzippedTarFile, Directory targetDirectory) {
|
void unpack(File gzippedTarFile, Directory targetDirectory) {
|
||||||
|
@ -21,6 +21,17 @@ const String kExecutable = 'foo';
|
|||||||
const String kPath1 = '/bar/bin/$kExecutable';
|
const String kPath1 = '/bar/bin/$kExecutable';
|
||||||
const String kPath2 = '/another/bin/$kExecutable';
|
const String kPath2 = '/another/bin/$kExecutable';
|
||||||
|
|
||||||
|
const String kPowershellException = r'''
|
||||||
|
New-Object : Exception calling ".ctor" with "3" argument(s): "End of Central Directory record could not be found."
|
||||||
|
At
|
||||||
|
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:934
|
||||||
|
char:23
|
||||||
|
+ ... ipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -Ar ...
|
||||||
|
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
|
||||||
|
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
|
||||||
|
''';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
MockProcessManager mockProcessManager;
|
MockProcessManager mockProcessManager;
|
||||||
|
|
||||||
@ -67,6 +78,7 @@ void main() {
|
|||||||
testWithoutContext('returns null when executable does not exist', () async {
|
testWithoutContext('returns null when executable does not exist', () async {
|
||||||
when(mockProcessManager.runSync(<String>['where', kExecutable]))
|
when(mockProcessManager.runSync(<String>['where', kExecutable]))
|
||||||
.thenReturn(ProcessResult(0, 1, null, null));
|
.thenReturn(ProcessResult(0, 1, null, null));
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
||||||
expect(utils.which(kExecutable), isNull);
|
expect(utils.which(kExecutable), isNull);
|
||||||
});
|
});
|
||||||
@ -74,6 +86,7 @@ void main() {
|
|||||||
testWithoutContext('returns exactly one result', () async {
|
testWithoutContext('returns exactly one result', () async {
|
||||||
when(mockProcessManager.runSync(<String>['where', 'foo']))
|
when(mockProcessManager.runSync(<String>['where', 'foo']))
|
||||||
.thenReturn(ProcessResult(0, 0, '$kPath1\n$kPath2', null));
|
.thenReturn(ProcessResult(0, 0, '$kPath1\n$kPath2', null));
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
||||||
expect(utils.which(kExecutable).path, kPath1);
|
expect(utils.which(kExecutable).path, kPath1);
|
||||||
});
|
});
|
||||||
@ -81,6 +94,7 @@ void main() {
|
|||||||
testWithoutContext('returns all results for whichAll', () async {
|
testWithoutContext('returns all results for whichAll', () async {
|
||||||
when(mockProcessManager.runSync(<String>['where', kExecutable]))
|
when(mockProcessManager.runSync(<String>['where', kExecutable]))
|
||||||
.thenReturn(ProcessResult(0, 0, '$kPath1\n$kPath2', null));
|
.thenReturn(ProcessResult(0, 0, '$kPath1\n$kPath2', null));
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows'));
|
||||||
final List<File> result = utils.whichAll(kExecutable);
|
final List<File> result = utils.whichAll(kExecutable);
|
||||||
expect(result, hasLength(2));
|
expect(result, hasLength(2));
|
||||||
@ -97,6 +111,7 @@ void main() {
|
|||||||
when(mockFile.readAsBytesSync()).thenThrow(
|
when(mockFile.readAsBytesSync()).thenThrow(
|
||||||
const FileSystemException('error'),
|
const FileSystemException('error'),
|
||||||
);
|
);
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
@ -116,6 +131,7 @@ void main() {
|
|||||||
0x01,
|
0x01,
|
||||||
0x02,
|
0x02,
|
||||||
]));
|
]));
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
@ -131,6 +147,7 @@ void main() {
|
|||||||
final MockFile mockFile = MockFile();
|
final MockFile mockFile = MockFile();
|
||||||
when(fileSystem.file(any)).thenReturn(mockFile);
|
when(fileSystem.file(any)).thenReturn(mockFile);
|
||||||
when(mockFile.readAsBytesSync()).thenReturn(Uint8List(0));
|
when(mockFile.readAsBytesSync()).thenReturn(Uint8List(0));
|
||||||
|
when(mockProcessManager.canRun('pwsh.exe')).thenReturn(true);
|
||||||
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
@ -142,6 +159,116 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Windows PowerShell Expand-Archive', () async {
|
||||||
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'pwsh.exe',
|
||||||
|
'-command',
|
||||||
|
'"Expand-Archive a -DestinationPath b"',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
|
||||||
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'windows'),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
osUtils.unzip(fileSystem.file('a'), fileSystem.directory('b'));
|
||||||
|
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Windows PowerShell Expand-Archive with stderr', () async {
|
||||||
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'pwsh.exe',
|
||||||
|
'-command',
|
||||||
|
'"Expand-Archive a -DestinationPath b"',
|
||||||
|
],
|
||||||
|
stderr: kPowershellException,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
|
||||||
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'windows'),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => osUtils.unzip(fileSystem.file('a'), fileSystem.directory('b')),
|
||||||
|
throwsA(isA<ProcessException>()));
|
||||||
|
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Windows PowerShell Compress-Archive', () {
|
||||||
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'pwsh.exe',
|
||||||
|
'-command',
|
||||||
|
'"Compress-Archive b -DestinationPath a"',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
|
||||||
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'windows'),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
osUtils.zip(fileSystem.directory('b'), fileSystem.file('a'));
|
||||||
|
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Windows PowerShell Compress-Archive with stderr', () {
|
||||||
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'pwsh.exe',
|
||||||
|
'-command',
|
||||||
|
'"Compress-Archive b -DestinationPath a"',
|
||||||
|
],
|
||||||
|
stderr: kPowershellException,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
|
||||||
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'windows'),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => osUtils.zip(fileSystem.directory('b'), fileSystem.file('a')),
|
||||||
|
throwsA(isA<ProcessException>()));
|
||||||
|
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Windows PowerShell verifyZip is a no-op', () {
|
||||||
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[]);
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
|
||||||
|
final OperatingSystemUtils osUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'windows'),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(osUtils.verifyZip(fileSystem.file('a')), true);
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('stream compression level', () {
|
testWithoutContext('stream compression level', () {
|
||||||
expect(OperatingSystemUtils.gzipLevel1.level, equals(1));
|
expect(OperatingSystemUtils.gzipLevel1.level, equals(1));
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user