-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Bsdtar + zstd fallback to prevent zstd hanging issue on windows #1237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
6349c3c
db3517f
27bf830
e9e146b
5f89653
ea98560
4fa5b7d
b3bd482
f9dfb05
54eb9b8
32b9582
32f5381
ffde3e4
2f73afa
39b7a86
1f33717
187781e
0822441
0fd856d
34f0143
2e5a517
424ae62
afbc5c0
8595831
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,18 +3,21 @@ import * as io from '@actions/io' | |
| import {existsSync, writeFileSync} from 'fs' | ||
| import * as path from 'path' | ||
| import * as utils from './cacheUtils' | ||
| import {CompressionMethod} from './constants' | ||
| import {CompressionMethod, SystemTarPathOnWindows} from './constants' | ||
|
|
||
| const IS_WINDOWS = process.platform === 'win32' | ||
|
|
||
| // Function also mutates the args array. For non-mutation call with passing an empty array. | ||
| async function getTarPath(args: string[]): Promise<string> { | ||
| switch (process.platform) { | ||
| case 'win32': { | ||
| const gnuTar = await utils.getGnuTarPathOnWindows() | ||
| const systemTar = `${process.env['windir']}\\System32\\tar.exe` | ||
| if (gnuTar) { | ||
| // Use GNUtar as default on windows | ||
| args.push('--force-local') | ||
| if (args.length > 0) { | ||
|
Phantsure marked this conversation as resolved.
Outdated
|
||
| args.push('--force-local') | ||
| } | ||
| return gnuTar | ||
| } else if (existsSync(systemTar)) { | ||
| return systemTar | ||
|
|
@@ -25,7 +28,9 @@ async function getTarPath(args: string[]): Promise<string> { | |
| const gnuTar = await io.which('gtar', false) | ||
| if (gnuTar) { | ||
| // fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527 | ||
| args.push('--delay-directory-restore') | ||
| if (args.length > 0) { | ||
| args.push('--delay-directory-restore') | ||
| } | ||
| return gnuTar | ||
| } | ||
| break | ||
|
|
@@ -49,18 +54,28 @@ function getWorkingDirectory(): string { | |
| } | ||
|
|
||
| // Common function for extractTar and listTar to get the compression method | ||
| function getCompressionProgram(compressionMethod: CompressionMethod): string[] { | ||
| async function getCompressionProgram( | ||
| compressionMethod: CompressionMethod | ||
| ): Promise<string[]> { | ||
| // -d: Decompress. | ||
| // unzstd is equivalent to 'zstd -d' | ||
| // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
| // Using 30 here because we also support 32-bit self-hosted runners. | ||
| const tarPath = await getTarPath([]) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getTarPath is only used for getting to know if
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. args set in getTarPath are only the ones related to particular os which also helps in deciding which tar to use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case we can break into two function - one to get tar path and another to to get archive command. |
||
| const BSD_TAR_ZSTD = IS_WINDOWS && tarPath === SystemTarPathOnWindows | ||
| switch (compressionMethod) { | ||
| case CompressionMethod.Zstd: | ||
| if (BSD_TAR_ZSTD) { | ||
| return ['-a'] // auto-detect compression | ||
|
Phantsure marked this conversation as resolved.
Outdated
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will auto-detection take care of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to be used for compression where information is taken from tar file extension. So I think it can't take care of that |
||
| } | ||
| return [ | ||
| '--use-compress-program', | ||
| IS_WINDOWS ? 'zstd -d --long=30' : 'unzstd --long=30' | ||
| ] | ||
| case CompressionMethod.ZstdWithoutLong: | ||
| if (BSD_TAR_ZSTD) { | ||
| return ['a'] // auto-detect compression | ||
| } | ||
| return ['--use-compress-program', IS_WINDOWS ? 'zstd -d' : 'unzstd'] | ||
| default: | ||
| return ['-z'] | ||
|
|
@@ -72,7 +87,7 @@ export async function listTar( | |
| compressionMethod: CompressionMethod | ||
| ): Promise<void> { | ||
| const args = [ | ||
| ...getCompressionProgram(compressionMethod), | ||
| ...(await getCompressionProgram(compressionMethod)), | ||
| '-tf', | ||
| archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
| '-P' | ||
|
|
@@ -88,7 +103,7 @@ export async function extractTar( | |
| const workingDirectory = getWorkingDirectory() | ||
| await io.mkdirP(workingDirectory) | ||
| const args = [ | ||
| ...getCompressionProgram(compressionMethod), | ||
| ...(await getCompressionProgram(compressionMethod)), | ||
| '-xf', | ||
| archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
| '-P', | ||
|
|
@@ -117,31 +132,43 @@ export async function createTar( | |
| // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
| // Using 30 here because we also support 32-bit self-hosted runners. | ||
| // Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd. | ||
| function getCompressionProgram(): string[] { | ||
| async function getCompressionProgram(): Promise<string[]> { | ||
| const tarPath = await getTarPath([]) | ||
| const BSD_TAR_ZSTD = IS_WINDOWS && tarPath === SystemTarPathOnWindows | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naming it
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense |
||
| switch (compressionMethod) { | ||
| case CompressionMethod.Zstd: | ||
| if (BSD_TAR_ZSTD) { | ||
| return ['-O', '|', 'zstd -T0 --long=30 -o'] | ||
| } | ||
| return [ | ||
| '--use-compress-program', | ||
| IS_WINDOWS ? 'zstd -T0 --long=30' : 'zstdmt --long=30' | ||
| IS_WINDOWS ? 'zstd -T0 --long=30' : 'zstdmt --long=30', | ||
| '-cf' | ||
| ] | ||
| case CompressionMethod.ZstdWithoutLong: | ||
| return ['--use-compress-program', IS_WINDOWS ? 'zstd -T0' : 'zstdmt'] | ||
| if (BSD_TAR_ZSTD) { | ||
| return ['-O', '|', 'zstd -T0 -o'] | ||
| } | ||
| return [ | ||
| '--use-compress-program', | ||
| IS_WINDOWS ? 'zstd -T0' : 'zstdmt', | ||
| '-cf' | ||
| ] | ||
| default: | ||
| return ['-z'] | ||
| return ['-z', '-cf'] | ||
| } | ||
| } | ||
| const args = [ | ||
| '--posix', | ||
| ...getCompressionProgram(), | ||
| '-cf', | ||
| cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
| '--exclude', | ||
| cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
| '-P', | ||
| '-C', | ||
| workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
| '--files-from', | ||
| manifestFilename | ||
| manifestFilename, | ||
| ...(await getCompressionProgram()), | ||
| cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does moving this args order have any negative effect on gnutar case or bsdtar on macos case? Essentially it would be good to idea to test all these existing scenarios for regression.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally it shouldn't affect. In windows case due to pipe symbol it is needed. I would take a look at it |
||
| ] | ||
| await execTar(args, archiveFolder) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.