Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions packages/cache/__tests__/tar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,62 @@ test('zstd extract tar with windows BSDtar', async () => {
}
})

test('zstd extract tar prefers BSDtar when opt-in env var set', async () => {
if (IS_WINDOWS) {
const mkdirMock = jest.spyOn(io, 'mkdirP')
const execMock = jest.spyOn(exec, 'exec')
// GNU tar still available — without the env var this would take the GNU path.
jest
.spyOn(utils, 'getGnuTarPathOnWindows')
.mockReturnValue(Promise.resolve(GnuTarPathOnWindows))
process.env['ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS'] = 'true'

Comment thread
zeitlinger marked this conversation as resolved.
try {
const archivePath = `${process.env['windir']}\\fakepath\\cache.tar`
const workspace = process.env['GITHUB_WORKSPACE']
const tarPath = SystemTarPathOnWindows

await tar.extractTar(archivePath, CompressionMethod.Zstd)

expect(mkdirMock).toHaveBeenCalledWith(workspace)
expect(execMock).toHaveBeenCalledTimes(2)

expect(execMock).toHaveBeenNthCalledWith(
1,
[
'zstd -d --long=30 --force -o',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
].join(' '),
undefined,
{
cwd: undefined,
env: expect.objectContaining(defaultEnv)
}
)

expect(execMock).toHaveBeenNthCalledWith(
2,
[
`"${tarPath}"`,
'-xf',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workspace?.replace(/\\/g, '/')
].join(' '),
undefined,
{
cwd: undefined,
env: expect.objectContaining(defaultEnv)
}
)
} finally {
delete process.env['ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS']
}
}
})

test('gzip extract tar', async () => {
const mkdirMock = jest.spyOn(io, 'mkdirP')
const execMock = jest.spyOn(exec, 'exec')
Expand Down
11 changes: 11 additions & 0 deletions packages/cache/src/internal/tar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ async function getTarPath(): Promise<ArchiveTool> {
case 'win32': {
const gnuTar = await utils.getGnuTarPathOnWindows()
const systemTar = SystemTarPathOnWindows
// Opt-in: prefer BSD tar (libarchive, shipped as
// C:\Windows\System32\tar.exe on Windows 10+). Benchmarks on hosted
// runners show ~4x faster extract on many-small-files payloads
Comment thread
zeitlinger marked this conversation as resolved.
Outdated
// compared to Git for Windows' MSYS GNU tar, because bsdtar makes
// native Win32 syscalls and has zstd built in (no external
// zstd.exe fork-per-file). See actions/cache#752 for context.
Comment thread
zeitlinger marked this conversation as resolved.
Outdated
const preferBsdTar =
process.env['ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS'] === 'true'
if (preferBsdTar && existsSync(systemTar)) {
return <ArchiveTool>{path: systemTar, type: ArchiveToolType.BSD}
}
if (gnuTar) {
// Use GNUtar as default on windows
return <ArchiveTool>{path: gnuTar, type: ArchiveToolType.GNU}
Expand Down
Loading