| "use strict"; |
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { |
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |
| return new (P || (P = Promise))(function (resolve, reject) { |
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } |
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } |
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } |
| step((generator = generator.apply(thisArg, _arguments || [])).next()); |
| }); |
| }; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| const core = require("@actions/core"); |
| const io = require("@actions/io"); |
| const fs = require("fs"); |
| const os = require("os"); |
| const path = require("path"); |
| const httpm = require("typed-rest-client/HttpClient"); |
| const semver = require("semver"); |
| const uuidV4 = require("uuid/v4"); |
| const exec_1 = require("@actions/exec/lib/exec"); |
| const assert_1 = require("assert"); |
| class HTTPError extends Error { |
| constructor(httpStatusCode) { |
| super(`Unexpected HTTP response: ${httpStatusCode}`); |
| this.httpStatusCode = httpStatusCode; |
| Object.setPrototypeOf(this, new.target.prototype); |
| } |
| } |
| exports.HTTPError = HTTPError; |
| const IS_WINDOWS = process.platform === 'win32'; |
| const userAgent = 'actions/tool-cache'; |
| // On load grab temp directory and cache directory and remove them from env (currently don't want to expose this) |
| let tempDirectory = process.env['RUNNER_TEMP'] || ''; |
| let cacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; |
| // If directories not found, place them in common temp locations |
| if (!tempDirectory || !cacheRoot) { |
| let baseLocation; |
| if (IS_WINDOWS) { |
| // On windows use the USERPROFILE env variable |
| baseLocation = process.env['USERPROFILE'] || 'C:\\'; |
| } |
| else { |
| if (process.platform === 'darwin') { |
| baseLocation = '/Users'; |
| } |
| else { |
| baseLocation = '/home'; |
| } |
| } |
| if (!tempDirectory) { |
| tempDirectory = path.join(baseLocation, 'actions', 'temp'); |
| } |
| if (!cacheRoot) { |
| cacheRoot = path.join(baseLocation, 'actions', 'cache'); |
| } |
| } |
| /** |
| * Download a tool from an url and stream it into a file |
| * |
| * @param url url of tool to download |
| * @returns path to downloaded tool |
| */ |
| function downloadTool(url) { |
| return __awaiter(this, void 0, void 0, function* () { |
| // Wrap in a promise so that we can resolve from within stream callbacks |
| return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { |
| try { |
| const http = new httpm.HttpClient(userAgent, [], { |
| allowRetries: true, |
| maxRetries: 3 |
| }); |
| const destPath = path.join(tempDirectory, uuidV4()); |
| yield io.mkdirP(tempDirectory); |
| core.debug(`Downloading ${url}`); |
| core.debug(`Downloading ${destPath}`); |
| if (fs.existsSync(destPath)) { |
| throw new Error(`Destination file path ${destPath} already exists`); |
| } |
| const response = yield http.get(url); |
| if (response.message.statusCode !== 200) { |
| const err = new HTTPError(response.message.statusCode); |
| core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); |
| throw err; |
| } |
| const file = fs.createWriteStream(destPath); |
| file.on('open', () => __awaiter(this, void 0, void 0, function* () { |
| try { |
| const stream = response.message.pipe(file); |
| stream.on('close', () => { |
| core.debug('download complete'); |
| resolve(destPath); |
| }); |
| } |
| catch (err) { |
| core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); |
| reject(err); |
| } |
| })); |
| file.on('error', err => { |
| file.end(); |
| reject(err); |
| }); |
| } |
| catch (err) { |
| reject(err); |
| } |
| })); |
| }); |
| } |
| exports.downloadTool = downloadTool; |
| /** |
| * Extract a .7z file |
| * |
| * @param file path to the .7z file |
| * @param dest destination directory. Optional. |
| * @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this |
| * problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will |
| * gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is |
| * bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line |
| * interface, it is smaller than the full command line interface, and it does support long paths. At the |
| * time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website. |
| * Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path |
| * to 7zr.exe can be pass to this function. |
| * @returns path to the destination directory |
| */ |
| function extract7z(file, dest, _7zPath) { |
| return __awaiter(this, void 0, void 0, function* () { |
| assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS'); |
| assert_1.ok(file, 'parameter "file" is required'); |
| dest = dest || (yield _createExtractFolder(dest)); |
| const originalCwd = process.cwd(); |
| process.chdir(dest); |
| if (_7zPath) { |
| try { |
| const args = [ |
| 'x', |
| '-bb1', |
| '-bd', |
| '-sccUTF-8', |
| file |
| ]; |
| const options = { |
| silent: true |
| }; |
| yield exec_1.exec(`"${_7zPath}"`, args, options); |
| } |
| finally { |
| process.chdir(originalCwd); |
| } |
| } |
| else { |
| const escapedScript = path |
| .join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1') |
| .replace(/'/g, "''") |
| .replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines |
| const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); |
| const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); |
| const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`; |
| const args = [ |
| '-NoLogo', |
| '-Sta', |
| '-NoProfile', |
| '-NonInteractive', |
| '-ExecutionPolicy', |
| 'Unrestricted', |
| '-Command', |
| command |
| ]; |
| const options = { |
| silent: true |
| }; |
| try { |
| const powershellPath = yield io.which('powershell', true); |
| yield exec_1.exec(`"${powershellPath}"`, args, options); |
| } |
| finally { |
| process.chdir(originalCwd); |
| } |
| } |
| return dest; |
| }); |
| } |
| exports.extract7z = extract7z; |
| /** |
| * Extract a tar |
| * |
| * @param file path to the tar |
| * @param dest destination directory. Optional. |
| * @param flags flags for the tar. Optional. |
| * @returns path to the destination directory |
| */ |
| function extractTar(file, dest, flags = 'xz') { |
| return __awaiter(this, void 0, void 0, function* () { |
| if (!file) { |
| throw new Error("parameter 'file' is required"); |
| } |
| dest = dest || (yield _createExtractFolder(dest)); |
| const tarPath = yield io.which('tar', true); |
| yield exec_1.exec(`"${tarPath}"`, [flags, '-C', dest, '-f', file]); |
| return dest; |
| }); |
| } |
| exports.extractTar = extractTar; |
| /** |
| * Extract a zip |
| * |
| * @param file path to the zip |
| * @param dest destination directory. Optional. |
| * @returns path to the destination directory |
| */ |
| function extractZip(file, dest) { |
| return __awaiter(this, void 0, void 0, function* () { |
| if (!file) { |
| throw new Error("parameter 'file' is required"); |
| } |
| dest = dest || (yield _createExtractFolder(dest)); |
| if (IS_WINDOWS) { |
| yield extractZipWin(file, dest); |
| } |
| else { |
| yield extractZipNix(file, dest); |
| } |
| return dest; |
| }); |
| } |
| exports.extractZip = extractZip; |
| function extractZipWin(file, dest) { |
| return __awaiter(this, void 0, void 0, function* () { |
| // build the powershell command |
| const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines |
| const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); |
| const command = `$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}')`; |
| // run powershell |
| const powershellPath = yield io.which('powershell'); |
| const args = [ |
| '-NoLogo', |
| '-Sta', |
| '-NoProfile', |
| '-NonInteractive', |
| '-ExecutionPolicy', |
| 'Unrestricted', |
| '-Command', |
| command |
| ]; |
| yield exec_1.exec(`"${powershellPath}"`, args); |
| }); |
| } |
| function extractZipNix(file, dest) { |
| return __awaiter(this, void 0, void 0, function* () { |
| const unzipPath = yield io.which('unzip'); |
| yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest }); |
| }); |
| } |
| /** |
| * Caches a directory and installs it into the tool cacheDir |
| * |
| * @param sourceDir the directory to cache into tools |
| * @param tool tool name |
| * @param version version of the tool. semver format |
| * @param arch architecture of the tool. Optional. Defaults to machine architecture |
| */ |
| function cacheDir(sourceDir, tool, version, arch) { |
| return __awaiter(this, void 0, void 0, function* () { |
| version = semver.clean(version) || version; |
| arch = arch || os.arch(); |
| core.debug(`Caching tool ${tool} ${version} ${arch}`); |
| core.debug(`source dir: ${sourceDir}`); |
| if (!fs.statSync(sourceDir).isDirectory()) { |
| throw new Error('sourceDir is not a directory'); |
| } |
| // Create the tool dir |
| const destPath = yield _createToolPath(tool, version, arch); |
| // copy each child item. do not move. move can fail on Windows |
| // due to anti-virus software having an open handle on a file. |
| for (const itemName of fs.readdirSync(sourceDir)) { |
| const s = path.join(sourceDir, itemName); |
| yield io.cp(s, destPath, { recursive: true }); |
| } |
| // write .complete |
| _completeToolPath(tool, version, arch); |
| return destPath; |
| }); |
| } |
| exports.cacheDir = cacheDir; |
| /** |
| * Caches a downloaded file (GUID) and installs it |
| * into the tool cache with a given targetName |
| * |
| * @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid. |
| * @param targetFile the name of the file name in the tools directory |
| * @param tool tool name |
| * @param version version of the tool. semver format |
| * @param arch architecture of the tool. Optional. Defaults to machine architecture |
| */ |
| function cacheFile(sourceFile, targetFile, tool, version, arch) { |
| return __awaiter(this, void 0, void 0, function* () { |
| version = semver.clean(version) || version; |
| arch = arch || os.arch(); |
| core.debug(`Caching tool ${tool} ${version} ${arch}`); |
| core.debug(`source file: ${sourceFile}`); |
| if (!fs.statSync(sourceFile).isFile()) { |
| throw new Error('sourceFile is not a file'); |
| } |
| // create the tool dir |
| const destFolder = yield _createToolPath(tool, version, arch); |
| // copy instead of move. move can fail on Windows due to |
| // anti-virus software having an open handle on a file. |
| const destPath = path.join(destFolder, targetFile); |
| core.debug(`destination file ${destPath}`); |
| yield io.cp(sourceFile, destPath); |
| // write .complete |
| _completeToolPath(tool, version, arch); |
| return destFolder; |
| }); |
| } |
| exports.cacheFile = cacheFile; |
| /** |
| * Finds the path to a tool version in the local installed tool cache |
| * |
| * @param toolName name of the tool |
| * @param versionSpec version of the tool |
| * @param arch optional arch. defaults to arch of computer |
| */ |
| function find(toolName, versionSpec, arch) { |
| if (!toolName) { |
| throw new Error('toolName parameter is required'); |
| } |
| if (!versionSpec) { |
| throw new Error('versionSpec parameter is required'); |
| } |
| arch = arch || os.arch(); |
| // attempt to resolve an explicit version |
| if (!_isExplicitVersion(versionSpec)) { |
| const localVersions = findAllVersions(toolName, arch); |
| const match = _evaluateVersions(localVersions, versionSpec); |
| versionSpec = match; |
| } |
| // check for the explicit version in the cache |
| let toolPath = ''; |
| if (versionSpec) { |
| versionSpec = semver.clean(versionSpec) || ''; |
| const cachePath = path.join(cacheRoot, toolName, versionSpec, arch); |
| core.debug(`checking cache: ${cachePath}`); |
| if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) { |
| core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`); |
| toolPath = cachePath; |
| } |
| else { |
| core.debug('not found'); |
| } |
| } |
| return toolPath; |
| } |
| exports.find = find; |
| /** |
| * Finds the paths to all versions of a tool that are installed in the local tool cache |
| * |
| * @param toolName name of the tool |
| * @param arch optional arch. defaults to arch of computer |
| */ |
| function findAllVersions(toolName, arch) { |
| const versions = []; |
| arch = arch || os.arch(); |
| const toolPath = path.join(cacheRoot, toolName); |
| if (fs.existsSync(toolPath)) { |
| const children = fs.readdirSync(toolPath); |
| for (const child of children) { |
| if (_isExplicitVersion(child)) { |
| const fullPath = path.join(toolPath, child, arch || ''); |
| if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) { |
| versions.push(child); |
| } |
| } |
| } |
| } |
| return versions; |
| } |
| exports.findAllVersions = findAllVersions; |
| function _createExtractFolder(dest) { |
| return __awaiter(this, void 0, void 0, function* () { |
| if (!dest) { |
| // create a temp dir |
| dest = path.join(tempDirectory, uuidV4()); |
| } |
| yield io.mkdirP(dest); |
| return dest; |
| }); |
| } |
| function _createToolPath(tool, version, arch) { |
| return __awaiter(this, void 0, void 0, function* () { |
| const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || ''); |
| core.debug(`destination ${folderPath}`); |
| const markerPath = `${folderPath}.complete`; |
| yield io.rmRF(folderPath); |
| yield io.rmRF(markerPath); |
| yield io.mkdirP(folderPath); |
| return folderPath; |
| }); |
| } |
| function _completeToolPath(tool, version, arch) { |
| const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || ''); |
| const markerPath = `${folderPath}.complete`; |
| fs.writeFileSync(markerPath, ''); |
| core.debug('finished caching tool'); |
| } |
| function _isExplicitVersion(versionSpec) { |
| const c = semver.clean(versionSpec) || ''; |
| core.debug(`isExplicit: ${c}`); |
| const valid = semver.valid(c) != null; |
| core.debug(`explicit? ${valid}`); |
| return valid; |
| } |
| function _evaluateVersions(versions, versionSpec) { |
| let version = ''; |
| core.debug(`evaluating ${versions.length} versions`); |
| versions = versions.sort((a, b) => { |
| if (semver.gt(a, b)) { |
| return 1; |
| } |
| return -1; |
| }); |
| for (let i = versions.length - 1; i >= 0; i--) { |
| const potential = versions[i]; |
| const satisfied = semver.satisfies(potential, versionSpec); |
| if (satisfied) { |
| version = potential; |
| break; |
| } |
| } |
| if (version) { |
| core.debug(`matched: ${version}`); |
| } |
| else { |
| core.debug('match not found'); |
| } |
| return version; |
| } |
| //# sourceMappingURL=tool-cache.js.map |