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
41 changes: 41 additions & 0 deletions packages/tool-cache/__tests__/tool-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,47 @@ describe('@actions/tool-cache', function() {
expect(fs.statSync(downPath).size).toBe(35)
})

it('downloads a 35 byte file (dest)', async () => {
const dest = 'test-download-file'
try {
const downPath: string = await tc.downloadTool(
'http://example.com/bytes/35',
dest
)

expect(downPath).toEqual(dest)
expect(fs.existsSync(downPath)).toBeTruthy()
expect(fs.statSync(downPath).size).toBe(35)
} finally {
try {
await fs.promises.unlink(dest)
} catch {
// intentionally empty
}
}
})

it('downloads a 35 byte file (dest requires mkdirp)', async () => {
const dest = 'test-download-dir/test-download-file'
try {
const downPath: string = await tc.downloadTool(
'http://example.com/bytes/35',
dest
)

expect(downPath).toEqual(dest)
expect(fs.existsSync(downPath)).toBeTruthy()
expect(fs.statSync(downPath).size).toBe(35)
} finally {
try {
await fs.promises.unlink(dest)
await fs.promises.rmdir(path.dirname(dest))
} catch {
// intentionally empty
}
}
})

it('downloads a 35 byte file after a redirect', async () => {
nock('http://example.com')
.get('/redirect-to')
Expand Down
21 changes: 12 additions & 9 deletions packages/tool-cache/src/tool-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,27 @@ if (!tempDirectory || !cacheRoot) {
* Download a tool from an url and stream it into a file
*
* @param url url of tool to download
* @param dest path to download tool
* @returns path to downloaded tool
Comment thread
ericsciple marked this conversation as resolved.
*/
export async function downloadTool(url: string): Promise<string> {
export async function downloadTool(
url: string,
dest?: string
): Promise<string> {
// Wrap in a promise so that we can resolve from within stream callbacks
return new Promise<string>(async (resolve, reject) => {
try {
const http = new httpm.HttpClient(userAgent, [], {
allowRetries: true,
maxRetries: 3
})
const destPath = path.join(tempDirectory, uuidV4())

await io.mkdirP(tempDirectory)
dest = dest || path.join(tempDirectory, uuidV4())
await io.mkdirP(path.dirname(dest))
core.debug(`Downloading ${url}`)
core.debug(`Downloading ${destPath}`)
core.debug(`Downloading ${dest}`)

if (fs.existsSync(destPath)) {
throw new Error(`Destination file path ${destPath} already exists`)
if (fs.existsSync(dest)) {
throw new Error(`Destination file path ${dest} already exists`)
}

const response: httpm.HttpClientResponse = await http.get(url)
Expand All @@ -80,13 +83,13 @@ export async function downloadTool(url: string): Promise<string> {
throw err
}

const file: NodeJS.WritableStream = fs.createWriteStream(destPath)
const file: NodeJS.WritableStream = fs.createWriteStream(dest)
file.on('open', async () => {
try {
const stream = response.message.pipe(file)
stream.on('close', () => {
core.debug('download complete')
resolve(destPath)
resolve(dest)
})
} catch (err) {
core.debug(
Expand Down