diff --git a/packages/cache/__tests__/tar.test.ts b/packages/cache/__tests__/tar.test.ts index 0aa6c784..63bd69ef 100644 --- a/packages/cache/__tests__/tar.test.ts +++ b/packages/cache/__tests__/tar.test.ts @@ -95,7 +95,7 @@ test('gzip extract GNU tar on windows', async () => { jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false) const isGnuMock = jest - .spyOn(utils, 'useGnuTar') + .spyOn(utils, 'isGnuTarInstalled') .mockReturnValue(Promise.resolve(true)) const execMock = jest.spyOn(exec, 'exec') const archivePath = `${process.env['windir']}\\fakepath\\cache.tar` diff --git a/packages/cache/src/internal/cacheUtils.ts b/packages/cache/src/internal/cacheUtils.ts index bd698286..ed230426 100644 --- a/packages/cache/src/internal/cacheUtils.ts +++ b/packages/cache/src/internal/cacheUtils.ts @@ -83,8 +83,8 @@ async function getVersion(app: string): Promise { // Use zstandard if possible to maximize cache performance export async function getCompressionMethod(): Promise { - if (process.platform === 'win32') { - // Disable zstd on windows due to bug https://github.com/actions/cache/issues/301 + if (process.platform === 'win32' && !isGnuTarInstalled()) { + // Disable zstd due to bug https://github.com/actions/cache/issues/301 return CompressionMethod.Gzip } else { const versionOutput = await getVersion('zstd') @@ -103,7 +103,7 @@ export function getCacheFileName(compressionMethod: CompressionMethod): string { : CacheFilename.Zstd } -export async function useGnuTar(): Promise { +export async function isGnuTarInstalled(): Promise { const versionOutput = await getVersion('tar') return versionOutput.toLowerCase().includes('gnu tar') } diff --git a/packages/cache/src/internal/tar.ts b/packages/cache/src/internal/tar.ts index 27fef40f..823139c1 100644 --- a/packages/cache/src/internal/tar.ts +++ b/packages/cache/src/internal/tar.ts @@ -5,23 +5,33 @@ import * as path from 'path' import * as utils from './cacheUtils' import {CompressionMethod} from './constants' -async function getTarPath(args: string[]): Promise { - // Explicitly use BSD Tar on Windows +async function getTarPath( + args: string[], + compressionMethod: CompressionMethod +): Promise { const IS_WINDOWS = process.platform === 'win32' if (IS_WINDOWS) { const systemTar = `${process.env['windir']}\\System32\\tar.exe` - if (existsSync(systemTar)) { + if (compressionMethod !== CompressionMethod.Gzip) { + // We only use zstandard compression on windows when gnu tar is installed due to + // a bug with compressing large files with bsdtar + zstd + args.push('--force-local') + } else if (existsSync(systemTar)) { return systemTar - } else if (await utils.useGnuTar()) { + } else if (await utils.isGnuTarInstalled()) { args.push('--force-local') } } return await io.which('tar', true) } -async function execTar(args: string[], cwd?: string): Promise { +async function execTar( + args: string[], + compressionMethod: CompressionMethod, + cwd?: string +): Promise { try { - await exec(`"${await getTarPath(args)}"`, args, {cwd}) + await exec(`"${await getTarPath(args, compressionMethod)}"`, args, {cwd}) } catch (error) { throw new Error(`Tar failed with error: ${error?.message}`) } @@ -59,7 +69,7 @@ export async function extractTar( '-C', workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/') ] - await execTar(args) + await execTar(args, compressionMethod) } export async function createTar( @@ -100,5 +110,5 @@ export async function createTar( '--files-from', manifestFilename ] - await execTar(args, archiveFolder) + await execTar(args, compressionMethod, archiveFolder) }