mirror of https://github.com/actions/cache.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import * as core from "@actions/core";
|
|
import { HttpClient, HttpClientResponse } from "@actions/http-client";
|
|
import { GetObjectCommand, S3Client, S3ClientConfig } from "@aws-sdk/client-s3";
|
|
import * as fs from "fs";
|
|
import * as stream from "stream";
|
|
import * as util from "util";
|
|
|
|
import * as utils from "./cacheUtils";
|
|
import { SocketTimeout } from "./cacheUtils";
|
|
import { retryHttpClientResponse } from "./requestUtils";
|
|
|
|
/**
|
|
* Pipes the body of a HTTP response to a stream
|
|
*
|
|
* @param response the HTTP response
|
|
* @param output the writable stream
|
|
*/
|
|
async function pipeResponseToStream(
|
|
response: HttpClientResponse,
|
|
output: NodeJS.WritableStream
|
|
): Promise<void> {
|
|
const pipeline = util.promisify(stream.pipeline);
|
|
await pipeline(response.message, output);
|
|
}
|
|
|
|
/**
|
|
* Download the cache using the Actions toolkit http-client
|
|
*
|
|
* @param archiveLocation the URL for the cache
|
|
* @param archivePath the local path where the cache is saved
|
|
*/
|
|
export async function downloadCacheHttpClient(
|
|
archiveLocation: string,
|
|
archivePath: string
|
|
): Promise<void> {
|
|
const writeStream = fs.createWriteStream(archivePath);
|
|
const httpClient = new HttpClient("actions/cache");
|
|
const downloadResponse = await retryHttpClientResponse(
|
|
"downloadCache",
|
|
async () => httpClient.get(archiveLocation)
|
|
);
|
|
|
|
// Abort download if no traffic received over the socket.
|
|
downloadResponse.message.socket.setTimeout(SocketTimeout, () => {
|
|
downloadResponse.message.destroy();
|
|
core.debug(
|
|
`Aborting download, socket timed out after ${SocketTimeout} ms`
|
|
);
|
|
});
|
|
|
|
await pipeResponseToStream(downloadResponse, writeStream);
|
|
|
|
// Validate download size.
|
|
const contentLengthHeader =
|
|
downloadResponse.message.headers["content-length"];
|
|
|
|
if (contentLengthHeader) {
|
|
const expectedLength = parseInt(contentLengthHeader);
|
|
const actualLength = utils.getArchiveFileSizeInBytes(archivePath);
|
|
|
|
if (actualLength !== expectedLength) {
|
|
throw new Error(
|
|
`Incomplete download. Expected file size: ${expectedLength}, actual file size: ${actualLength}`
|
|
);
|
|
}
|
|
} else {
|
|
core.debug("Unable to validate download, no Content-Length header");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Download the cache using the AWS S3. Only call this method if the use S3.
|
|
*
|
|
* @param key the key for the cache in S3
|
|
* @param archivePath the local path where the cache is saved
|
|
* @param s3Options: the option for AWS S3 client
|
|
* @param s3BucketName: the name of bucket in AWS S3
|
|
*/
|
|
export async function downloadCacheStorageS3(
|
|
key: string,
|
|
archivePath: string,
|
|
s3Options: S3ClientConfig,
|
|
s3BucketName: string
|
|
): Promise<void> {
|
|
const s3client = new S3Client(s3Options);
|
|
const param = {
|
|
Bucket: s3BucketName,
|
|
Key: key
|
|
};
|
|
|
|
const response = await s3client.send(new GetObjectCommand(param));
|
|
if (!response.Body) {
|
|
throw new Error(
|
|
`Incomplete download. response.Body is undefined from S3.`
|
|
);
|
|
}
|
|
|
|
const fileStream = fs.createWriteStream(archivePath);
|
|
|
|
const pipeline = util.promisify(stream.pipeline);
|
|
await pipeline(response.Body as stream.Readable, fileStream);
|
|
|
|
return;
|
|
}
|