Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Binary file modified packages/tool-cache/__tests__/data/test.tar.gz
Binary file not shown.
144 changes: 68 additions & 76 deletions packages/tool-cache/__tests__/tool-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,96 +268,88 @@ describe('@actions/tool-cache', function() {
await io.rmRF(tempDir)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i had to recreate test.tar.gz with the option --format pax otherwise bsdtar doesnt preserve UTF file names correctly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i added a README.txt to the archive for future reference

}
})
} else {
it('extract .tar.gz', async () => {
const tempDir = path.join(tempPath, 'test-install-tar.gz')
}

await io.mkdirP(tempDir)
it('extract .tar.gz', async () => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no changes here, just eliminated the else condition and de-indented

const tempDir = path.join(tempPath, 'test-install-tar.gz')

// copy the .tar.gz file to the test dir
const _tgzFile: string = path.join(tempDir, 'test.tar.gz')
await io.cp(path.join(__dirname, 'data', 'test.tar.gz'), _tgzFile)
await io.mkdirP(tempDir)

// extract/cache
const extPath: string = await tc.extractTar(_tgzFile)
await tc.cacheDir(extPath, 'my-tgz-contents', '1.1.0')
const toolPath: string = tc.find('my-tgz-contents', '1.1.0')
// copy the .tar.gz file to the test dir
const _tgzFile: string = path.join(tempDir, 'test.tar.gz')
await io.cp(path.join(__dirname, 'data', 'test.tar.gz'), _tgzFile)

expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'file.txt'))).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'file-with-ç-character.txt'))
).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'folder', 'nested-file.txt'))
).toBeTruthy()
expect(
fs.readFileSync(
path.join(toolPath, 'folder', 'nested-file.txt'),
'utf8'
)
).toBe('folder/nested-file.txt contents')
})
// extract/cache
const extPath: string = await tc.extractTar(_tgzFile)
await tc.cacheDir(extPath, 'my-tgz-contents', '1.1.0')
const toolPath: string = tc.find('my-tgz-contents', '1.1.0')

it('extract .tar.gz to a directory that does not exist', async () => {
const tempDir = path.join(tempPath, 'test-install-tar.gz')
const destDir = path.join(tempDir, 'not-exist')
expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'file.txt'))).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'file-with-ç-character.txt'))
).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'folder', 'nested-file.txt'))
).toBeTruthy()
expect(
fs.readFileSync(path.join(toolPath, 'folder', 'nested-file.txt'), 'utf8')
).toBe('folder/nested-file.txt contents')
})

await io.mkdirP(tempDir)
it('extract .tar.gz to a directory that does not exist', async () => {
const tempDir = path.join(tempPath, 'test-install-tar.gz')
const destDir = path.join(tempDir, 'not-exist')

// copy the .tar.gz file to the test dir
const _tgzFile: string = path.join(tempDir, 'test.tar.gz')
await io.cp(path.join(__dirname, 'data', 'test.tar.gz'), _tgzFile)
await io.mkdirP(tempDir)

// extract/cache
const extPath: string = await tc.extractTar(_tgzFile, destDir)
await tc.cacheDir(extPath, 'my-tgz-contents', '1.1.0')
const toolPath: string = tc.find('my-tgz-contents', '1.1.0')
// copy the .tar.gz file to the test dir
const _tgzFile: string = path.join(tempDir, 'test.tar.gz')
await io.cp(path.join(__dirname, 'data', 'test.tar.gz'), _tgzFile)

expect(extPath).toContain('not-exist')
expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'file.txt'))).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'file-with-ç-character.txt'))
).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'folder', 'nested-file.txt'))
).toBeTruthy()
expect(
fs.readFileSync(
path.join(toolPath, 'folder', 'nested-file.txt'),
'utf8'
)
).toBe('folder/nested-file.txt contents')
})
// extract/cache
const extPath: string = await tc.extractTar(_tgzFile, destDir)
await tc.cacheDir(extPath, 'my-tgz-contents', '1.1.0')
const toolPath: string = tc.find('my-tgz-contents', '1.1.0')

it('extract .tar.xz', async () => {
const tempDir = path.join(tempPath, 'test-install-tar.xz')
expect(extPath).toContain('not-exist')
expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'file.txt'))).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'file-with-ç-character.txt'))
).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'folder', 'nested-file.txt'))
).toBeTruthy()
expect(
fs.readFileSync(path.join(toolPath, 'folder', 'nested-file.txt'), 'utf8')
).toBe('folder/nested-file.txt contents')
})

await io.mkdirP(tempDir)
it('extract .tar.xz', async () => {
const tempDir = path.join(tempPath, 'test-install-tar.xz')

// copy the .tar.gz file to the test dir
const _txzFile: string = path.join(tempDir, 'test.tar.xz')
await io.cp(path.join(__dirname, 'data', 'test.tar.xz'), _txzFile)
await io.mkdirP(tempDir)

// extract/cache
const extPath: string = await tc.extractTar(_txzFile, undefined, 'x')
await tc.cacheDir(extPath, 'my-txz-contents', '1.1.0')
const toolPath: string = tc.find('my-txz-contents', '1.1.0')
// copy the .tar.gz file to the test dir
const _txzFile: string = path.join(tempDir, 'test.tar.xz')
await io.cp(path.join(__dirname, 'data', 'test.tar.xz'), _txzFile)

expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'bar.txt'))).toBeTruthy()
expect(
fs.existsSync(path.join(toolPath, 'foo', 'hello.txt'))
).toBeTruthy()
expect(
fs.readFileSync(path.join(toolPath, 'foo', 'hello.txt'), 'utf8')
).toBe('foo/hello: world')
})
}
// extract/cache
const extPath: string = await tc.extractTar(_txzFile, undefined, 'x')
await tc.cacheDir(extPath, 'my-txz-contents', '1.1.0')
const toolPath: string = tc.find('my-txz-contents', '1.1.0')

expect(fs.existsSync(toolPath)).toBeTruthy()
expect(fs.existsSync(`${toolPath}.complete`)).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'bar.txt'))).toBeTruthy()
expect(fs.existsSync(path.join(toolPath, 'foo', 'hello.txt'))).toBeTruthy()
expect(
fs.readFileSync(path.join(toolPath, 'foo', 'hello.txt'), 'utf8')
).toBe('foo/hello: world')
})

it('installs a zip and finds it', async () => {
const tempDir = path.join(__dirname, 'test-install-zip')
Expand Down
36 changes: 34 additions & 2 deletions packages/tool-cache/src/tool-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,41 @@ export async function extractTar(
throw new Error("parameter 'file' is required")
}

// Create dest
dest = await _createExtractFolder(dest)
const tarPath: string = await io.which('tar', true)
await exec(`"${tarPath}"`, [flags, '-C', dest, '-f', file])

// Determine whether GNU tar
let versionOutput = ''
await exec('tar --version', [], {
ignoreReturnCode: true,
listeners: {
stdout: (data: Buffer) => (versionOutput += data.toString()),
stderr: (data: Buffer) => (versionOutput += data.toString())
}
})
const isGnuTar = versionOutput.toUpperCase().includes('GNU TAR')
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider debugging this so we can troubleshoot easier if for some reason this breaks. (Analyzing text output of a cli can be a little fragile)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the output flows to the console too, so we're good wrt that aspect


// Initialize args
const args = [flags]

let destArg = dest
let fileArg = file
if (IS_WINDOWS && isGnuTar) {
args.push('--force-local')
destArg = dest.replace(/\\/g, '/')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both destArg and file need the \ replacement

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add for file too, but when i tested file doesnt appear to be required

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll push this change, aesthetically it will look good for consistency


// Technically only the dest needs to have `/` but for aesthetic consistency
// convert slashes in the file arg too.
fileArg = file.replace(/\\/g, '/')
}

if (isGnuTar) {
// Suppress warnings when using GNU tar to extract archives created by BSD tar
args.push('--warning=no-unknown-keyword')
}

args.push('-C', destArg, '-f', fileArg)
await exec(`tar`, args)

return dest
}
Expand Down