mirror of https://github.com/actions/toolkit
tool-cache: Support for extracting xar compatible archives (#207)
* Test xar extraction
* Support for extracting xar compatible archives
* Only allow extractXar on mac
* Create xar during test instead of using prebuilt
* Update lockfiles
* Add verbose flag if debug
* Add extractXar example to readme
* Revert "Update lockfiles"
This reverts commit a6cbddccf6
.
* Use node pkg in example
* Remove and ignore prebuilt xar
* Tests for non-existing dir and without flags
* Better arguments handling
* Make sure that target directory exists
Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
pull/519/head
parent
7e1c59c51e
commit
2710592b73
|
@ -3,4 +3,5 @@ packages/*/node_modules/
|
||||||
packages/*/lib/
|
packages/*/lib/
|
||||||
packages/*/__tests__/_temp/
|
packages/*/__tests__/_temp/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*.xar
|
||||||
packages/*/audit.json
|
packages/*/audit.json
|
||||||
|
|
|
@ -29,6 +29,10 @@ if (process.platform === 'win32') {
|
||||||
const node12Path = await tc.downloadTool('https://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.7z');
|
const node12Path = await tc.downloadTool('https://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.7z');
|
||||||
const node12ExtractedFolder = await tc.extract7z(node12Path, 'path/to/extract/to');
|
const node12ExtractedFolder = await tc.extract7z(node12Path, 'path/to/extract/to');
|
||||||
}
|
}
|
||||||
|
else if (process.platform === 'darwin') {
|
||||||
|
const node12Path = await tc.downloadTool('https://nodejs.org/dist/v12.7.0/node-v12.7.0.pkg');
|
||||||
|
const node12ExtractedFolder = await tc.extractXar(node12Path, 'path/to/extract/to');
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
const node12Path = await tc.downloadTool('https://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz');
|
const node12Path = await tc.downloadTool('https://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz');
|
||||||
const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to');
|
const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to');
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
file-with-ç-character.txt
|
|
@ -0,0 +1 @@
|
||||||
|
file.txt contents
|
|
@ -0,0 +1 @@
|
||||||
|
folder/nested-file.txt contents
|
|
@ -15,6 +15,7 @@ process.env['RUNNER_TOOL_CACHE'] = cachePath
|
||||||
import * as tc from '../src/tool-cache'
|
import * as tc from '../src/tool-cache'
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
const IS_MAC = process.platform === 'darwin'
|
||||||
|
|
||||||
describe('@actions/tool-cache', function() {
|
describe('@actions/tool-cache', function() {
|
||||||
beforeAll(function() {
|
beforeAll(function() {
|
||||||
|
@ -346,6 +347,110 @@ describe('@actions/tool-cache', function() {
|
||||||
await io.rmRF(tempDir)
|
await io.rmRF(tempDir)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else if (IS_MAC) {
|
||||||
|
it('extract .xar', async () => {
|
||||||
|
const tempDir = path.join(tempPath, 'test-install.xar')
|
||||||
|
const sourcePath = path.join(__dirname, 'data', 'archive-content')
|
||||||
|
const targetPath = path.join(tempDir, 'test.xar')
|
||||||
|
await io.mkdirP(tempDir)
|
||||||
|
|
||||||
|
// Create test archive
|
||||||
|
const xarPath = await io.which('xar', true)
|
||||||
|
await exec.exec(`${xarPath}`, ['-cf', targetPath, '.'], {
|
||||||
|
cwd: sourcePath
|
||||||
|
})
|
||||||
|
|
||||||
|
// extract/cache
|
||||||
|
const extPath: string = await tc.extractXar(targetPath, undefined, '-x')
|
||||||
|
await tc.cacheDir(extPath, 'my-xar-contents', '1.1.0')
|
||||||
|
const toolPath: string = tc.find('my-xar-contents', '1.1.0')
|
||||||
|
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('extract .xar to a directory that does not exist', async () => {
|
||||||
|
const tempDir = path.join(tempPath, 'test-install.xar')
|
||||||
|
const sourcePath = path.join(__dirname, 'data', 'archive-content')
|
||||||
|
const targetPath = path.join(tempDir, 'test.xar')
|
||||||
|
await io.mkdirP(tempDir)
|
||||||
|
|
||||||
|
const destDir = path.join(tempDir, 'not-exist')
|
||||||
|
|
||||||
|
// Create test archive
|
||||||
|
const xarPath = await io.which('xar', true)
|
||||||
|
await exec.exec(`${xarPath}`, ['-cf', targetPath, '.'], {
|
||||||
|
cwd: sourcePath
|
||||||
|
})
|
||||||
|
|
||||||
|
// extract/cache
|
||||||
|
const extPath: string = await tc.extractXar(targetPath, destDir, '-x')
|
||||||
|
await tc.cacheDir(extPath, 'my-xar-contents', '1.1.0')
|
||||||
|
const toolPath: string = tc.find('my-xar-contents', '1.1.0')
|
||||||
|
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('extract .xar without flags', async () => {
|
||||||
|
const tempDir = path.join(tempPath, 'test-install.xar')
|
||||||
|
const sourcePath = path.join(__dirname, 'data', 'archive-content')
|
||||||
|
const targetPath = path.join(tempDir, 'test.xar')
|
||||||
|
await io.mkdirP(tempDir)
|
||||||
|
|
||||||
|
// Create test archive
|
||||||
|
const xarPath = await io.which('xar', true)
|
||||||
|
await exec.exec(`${xarPath}`, ['-cf', targetPath, '.'], {
|
||||||
|
cwd: sourcePath
|
||||||
|
})
|
||||||
|
|
||||||
|
// extract/cache
|
||||||
|
const extPath: string = await tc.extractXar(targetPath, undefined)
|
||||||
|
await tc.cacheDir(extPath, 'my-xar-contents', '1.1.0')
|
||||||
|
const toolPath: string = tc.find('my-xar-contents', '1.1.0')
|
||||||
|
|
||||||
|
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')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
it('extract .tar.gz', async () => {
|
it('extract .tar.gz', async () => {
|
||||||
|
|
|
@ -23,6 +23,7 @@ export class HTTPError extends Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
const IS_MAC = process.platform === 'darwin'
|
||||||
const userAgent = 'actions/tool-cache'
|
const userAgent = 'actions/tool-cache'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -276,6 +277,43 @@ export async function extractTar(
|
||||||
return dest
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a xar compatible archive
|
||||||
|
*
|
||||||
|
* @param file path to the archive
|
||||||
|
* @param dest destination directory. Optional.
|
||||||
|
* @param flags flags for the xar. Optional.
|
||||||
|
* @returns path to the destination directory
|
||||||
|
*/
|
||||||
|
export async function extractXar(
|
||||||
|
file: string,
|
||||||
|
dest?: string,
|
||||||
|
flags: string | string[] = []
|
||||||
|
): Promise<string> {
|
||||||
|
ok(IS_MAC, 'extractXar() not supported on current OS')
|
||||||
|
ok(file, 'parameter "file" is required')
|
||||||
|
|
||||||
|
dest = await _createExtractFolder(dest)
|
||||||
|
|
||||||
|
let args: string[]
|
||||||
|
if (flags instanceof Array) {
|
||||||
|
args = flags
|
||||||
|
} else {
|
||||||
|
args = [flags]
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push('-x', '-C', dest, '-f', file)
|
||||||
|
|
||||||
|
if (core.isDebug()) {
|
||||||
|
args.push('-v')
|
||||||
|
}
|
||||||
|
|
||||||
|
const xarPath: string = await io.which('xar', true)
|
||||||
|
await exec(`"${xarPath}"`, _unique(args))
|
||||||
|
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract a zip
|
* Extract a zip
|
||||||
*
|
*
|
||||||
|
@ -675,3 +713,11 @@ function _getGlobal<T>(key: string, defaultValue: T): T {
|
||||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||||
return value !== undefined ? value : defaultValue
|
return value !== undefined ? value : defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of unique values.
|
||||||
|
* @param values Values to make unique.
|
||||||
|
*/
|
||||||
|
function _unique<T>(values: T[]): T[] {
|
||||||
|
return Array.from(new Set(values))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue