github.com/jfrog/frogbot@v1.1.1-0.20231221090046-821a26f50338/action/node_modules/@actions/tool-cache/lib/tool-cache.js (about)

     1  "use strict";
     2  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
     3      if (k2 === undefined) k2 = k;
     4      Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
     5  }) : (function(o, m, k, k2) {
     6      if (k2 === undefined) k2 = k;
     7      o[k2] = m[k];
     8  }));
     9  var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    10      Object.defineProperty(o, "default", { enumerable: true, value: v });
    11  }) : function(o, v) {
    12      o["default"] = v;
    13  });
    14  var __importStar = (this && this.__importStar) || function (mod) {
    15      if (mod && mod.__esModule) return mod;
    16      var result = {};
    17      if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    18      __setModuleDefault(result, mod);
    19      return result;
    20  };
    21  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    22      function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    23      return new (P || (P = Promise))(function (resolve, reject) {
    24          function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
    25          function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
    26          function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
    27          step((generator = generator.apply(thisArg, _arguments || [])).next());
    28      });
    29  };
    30  var __importDefault = (this && this.__importDefault) || function (mod) {
    31      return (mod && mod.__esModule) ? mod : { "default": mod };
    32  };
    33  Object.defineProperty(exports, "__esModule", { value: true });
    34  exports.evaluateVersions = exports.isExplicitVersion = exports.findFromManifest = exports.getManifestFromRepo = exports.findAllVersions = exports.find = exports.cacheFile = exports.cacheDir = exports.extractZip = exports.extractXar = exports.extractTar = exports.extract7z = exports.downloadTool = exports.HTTPError = void 0;
    35  const core = __importStar(require("@actions/core"));
    36  const io = __importStar(require("@actions/io"));
    37  const fs = __importStar(require("fs"));
    38  const mm = __importStar(require("./manifest"));
    39  const os = __importStar(require("os"));
    40  const path = __importStar(require("path"));
    41  const httpm = __importStar(require("@actions/http-client"));
    42  const semver = __importStar(require("semver"));
    43  const stream = __importStar(require("stream"));
    44  const util = __importStar(require("util"));
    45  const assert_1 = require("assert");
    46  const v4_1 = __importDefault(require("uuid/v4"));
    47  const exec_1 = require("@actions/exec/lib/exec");
    48  const retry_helper_1 = require("./retry-helper");
    49  class HTTPError extends Error {
    50      constructor(httpStatusCode) {
    51          super(`Unexpected HTTP response: ${httpStatusCode}`);
    52          this.httpStatusCode = httpStatusCode;
    53          Object.setPrototypeOf(this, new.target.prototype);
    54      }
    55  }
    56  exports.HTTPError = HTTPError;
    57  const IS_WINDOWS = process.platform === 'win32';
    58  const IS_MAC = process.platform === 'darwin';
    59  const userAgent = 'actions/tool-cache';
    60  /**
    61   * Download a tool from an url and stream it into a file
    62   *
    63   * @param url       url of tool to download
    64   * @param dest      path to download tool
    65   * @param auth      authorization header
    66   * @param headers   other headers
    67   * @returns         path to downloaded tool
    68   */
    69  function downloadTool(url, dest, auth, headers) {
    70      return __awaiter(this, void 0, void 0, function* () {
    71          dest = dest || path.join(_getTempDirectory(), v4_1.default());
    72          yield io.mkdirP(path.dirname(dest));
    73          core.debug(`Downloading ${url}`);
    74          core.debug(`Destination ${dest}`);
    75          const maxAttempts = 3;
    76          const minSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MIN_SECONDS', 10);
    77          const maxSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS', 20);
    78          const retryHelper = new retry_helper_1.RetryHelper(maxAttempts, minSeconds, maxSeconds);
    79          return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
    80              return yield downloadToolAttempt(url, dest || '', auth, headers);
    81          }), (err) => {
    82              if (err instanceof HTTPError && err.httpStatusCode) {
    83                  // Don't retry anything less than 500, except 408 Request Timeout and 429 Too Many Requests
    84                  if (err.httpStatusCode < 500 &&
    85                      err.httpStatusCode !== 408 &&
    86                      err.httpStatusCode !== 429) {
    87                      return false;
    88                  }
    89              }
    90              // Otherwise retry
    91              return true;
    92          });
    93      });
    94  }
    95  exports.downloadTool = downloadTool;
    96  function downloadToolAttempt(url, dest, auth, headers) {
    97      return __awaiter(this, void 0, void 0, function* () {
    98          if (fs.existsSync(dest)) {
    99              throw new Error(`Destination file path ${dest} already exists`);
   100          }
   101          // Get the response headers
   102          const http = new httpm.HttpClient(userAgent, [], {
   103              allowRetries: false
   104          });
   105          if (auth) {
   106              core.debug('set auth');
   107              if (headers === undefined) {
   108                  headers = {};
   109              }
   110              headers.authorization = auth;
   111          }
   112          const response = yield http.get(url, headers);
   113          if (response.message.statusCode !== 200) {
   114              const err = new HTTPError(response.message.statusCode);
   115              core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
   116              throw err;
   117          }
   118          // Download the response body
   119          const pipeline = util.promisify(stream.pipeline);
   120          const responseMessageFactory = _getGlobal('TEST_DOWNLOAD_TOOL_RESPONSE_MESSAGE_FACTORY', () => response.message);
   121          const readStream = responseMessageFactory();
   122          let succeeded = false;
   123          try {
   124              yield pipeline(readStream, fs.createWriteStream(dest));
   125              core.debug('download complete');
   126              succeeded = true;
   127              return dest;
   128          }
   129          finally {
   130              // Error, delete dest before retry
   131              if (!succeeded) {
   132                  core.debug('download failed');
   133                  try {
   134                      yield io.rmRF(dest);
   135                  }
   136                  catch (err) {
   137                      core.debug(`Failed to delete '${dest}'. ${err.message}`);
   138                  }
   139              }
   140          }
   141      });
   142  }
   143  /**
   144   * Extract a .7z file
   145   *
   146   * @param file     path to the .7z file
   147   * @param dest     destination directory. Optional.
   148   * @param _7zPath  path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this
   149   * problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will
   150   * gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is
   151   * bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line
   152   * interface, it is smaller than the full command line interface, and it does support long paths. At the
   153   * time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website.
   154   * Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path
   155   * to 7zr.exe can be pass to this function.
   156   * @returns        path to the destination directory
   157   */
   158  function extract7z(file, dest, _7zPath) {
   159      return __awaiter(this, void 0, void 0, function* () {
   160          assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS');
   161          assert_1.ok(file, 'parameter "file" is required');
   162          dest = yield _createExtractFolder(dest);
   163          const originalCwd = process.cwd();
   164          process.chdir(dest);
   165          if (_7zPath) {
   166              try {
   167                  const logLevel = core.isDebug() ? '-bb1' : '-bb0';
   168                  const args = [
   169                      'x',
   170                      logLevel,
   171                      '-bd',
   172                      '-sccUTF-8',
   173                      file
   174                  ];
   175                  const options = {
   176                      silent: true
   177                  };
   178                  yield exec_1.exec(`"${_7zPath}"`, args, options);
   179              }
   180              finally {
   181                  process.chdir(originalCwd);
   182              }
   183          }
   184          else {
   185              const escapedScript = path
   186                  .join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1')
   187                  .replace(/'/g, "''")
   188                  .replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
   189              const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, '');
   190              const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
   191              const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`;
   192              const args = [
   193                  '-NoLogo',
   194                  '-Sta',
   195                  '-NoProfile',
   196                  '-NonInteractive',
   197                  '-ExecutionPolicy',
   198                  'Unrestricted',
   199                  '-Command',
   200                  command
   201              ];
   202              const options = {
   203                  silent: true
   204              };
   205              try {
   206                  const powershellPath = yield io.which('powershell', true);
   207                  yield exec_1.exec(`"${powershellPath}"`, args, options);
   208              }
   209              finally {
   210                  process.chdir(originalCwd);
   211              }
   212          }
   213          return dest;
   214      });
   215  }
   216  exports.extract7z = extract7z;
   217  /**
   218   * Extract a compressed tar archive
   219   *
   220   * @param file     path to the tar
   221   * @param dest     destination directory. Optional.
   222   * @param flags    flags for the tar command to use for extraction. Defaults to 'xz' (extracting gzipped tars). Optional.
   223   * @returns        path to the destination directory
   224   */
   225  function extractTar(file, dest, flags = 'xz') {
   226      return __awaiter(this, void 0, void 0, function* () {
   227          if (!file) {
   228              throw new Error("parameter 'file' is required");
   229          }
   230          // Create dest
   231          dest = yield _createExtractFolder(dest);
   232          // Determine whether GNU tar
   233          core.debug('Checking tar --version');
   234          let versionOutput = '';
   235          yield exec_1.exec('tar --version', [], {
   236              ignoreReturnCode: true,
   237              silent: true,
   238              listeners: {
   239                  stdout: (data) => (versionOutput += data.toString()),
   240                  stderr: (data) => (versionOutput += data.toString())
   241              }
   242          });
   243          core.debug(versionOutput.trim());
   244          const isGnuTar = versionOutput.toUpperCase().includes('GNU TAR');
   245          // Initialize args
   246          let args;
   247          if (flags instanceof Array) {
   248              args = flags;
   249          }
   250          else {
   251              args = [flags];
   252          }
   253          if (core.isDebug() && !flags.includes('v')) {
   254              args.push('-v');
   255          }
   256          let destArg = dest;
   257          let fileArg = file;
   258          if (IS_WINDOWS && isGnuTar) {
   259              args.push('--force-local');
   260              destArg = dest.replace(/\\/g, '/');
   261              // Technically only the dest needs to have `/` but for aesthetic consistency
   262              // convert slashes in the file arg too.
   263              fileArg = file.replace(/\\/g, '/');
   264          }
   265          if (isGnuTar) {
   266              // Suppress warnings when using GNU tar to extract archives created by BSD tar
   267              args.push('--warning=no-unknown-keyword');
   268              args.push('--overwrite');
   269          }
   270          args.push('-C', destArg, '-f', fileArg);
   271          yield exec_1.exec(`tar`, args);
   272          return dest;
   273      });
   274  }
   275  exports.extractTar = extractTar;
   276  /**
   277   * Extract a xar compatible archive
   278   *
   279   * @param file     path to the archive
   280   * @param dest     destination directory. Optional.
   281   * @param flags    flags for the xar. Optional.
   282   * @returns        path to the destination directory
   283   */
   284  function extractXar(file, dest, flags = []) {
   285      return __awaiter(this, void 0, void 0, function* () {
   286          assert_1.ok(IS_MAC, 'extractXar() not supported on current OS');
   287          assert_1.ok(file, 'parameter "file" is required');
   288          dest = yield _createExtractFolder(dest);
   289          let args;
   290          if (flags instanceof Array) {
   291              args = flags;
   292          }
   293          else {
   294              args = [flags];
   295          }
   296          args.push('-x', '-C', dest, '-f', file);
   297          if (core.isDebug()) {
   298              args.push('-v');
   299          }
   300          const xarPath = yield io.which('xar', true);
   301          yield exec_1.exec(`"${xarPath}"`, _unique(args));
   302          return dest;
   303      });
   304  }
   305  exports.extractXar = extractXar;
   306  /**
   307   * Extract a zip
   308   *
   309   * @param file     path to the zip
   310   * @param dest     destination directory. Optional.
   311   * @returns        path to the destination directory
   312   */
   313  function extractZip(file, dest) {
   314      return __awaiter(this, void 0, void 0, function* () {
   315          if (!file) {
   316              throw new Error("parameter 'file' is required");
   317          }
   318          dest = yield _createExtractFolder(dest);
   319          if (IS_WINDOWS) {
   320              yield extractZipWin(file, dest);
   321          }
   322          else {
   323              yield extractZipNix(file, dest);
   324          }
   325          return dest;
   326      });
   327  }
   328  exports.extractZip = extractZip;
   329  function extractZipWin(file, dest) {
   330      return __awaiter(this, void 0, void 0, function* () {
   331          // build the powershell command
   332          const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
   333          const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
   334          const pwshPath = yield io.which('pwsh', false);
   335          //To match the file overwrite behavior on nix systems, we use the overwrite = true flag for ExtractToDirectory
   336          //and the -Force flag for Expand-Archive as a fallback
   337          if (pwshPath) {
   338              //attempt to use pwsh with ExtractToDirectory, if this fails attempt Expand-Archive
   339              const pwshCommand = [
   340                  `$ErrorActionPreference = 'Stop' ;`,
   341                  `try { Add-Type -AssemblyName System.IO.Compression.ZipFile } catch { } ;`,
   342                  `try { [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}', $true) }`,
   343                  `catch { if (($_.Exception.GetType().FullName -eq 'System.Management.Automation.MethodException') -or ($_.Exception.GetType().FullName -eq 'System.Management.Automation.RuntimeException') ){ Expand-Archive -LiteralPath '${escapedFile}' -DestinationPath '${escapedDest}' -Force } else { throw $_ } } ;`
   344              ].join(' ');
   345              const args = [
   346                  '-NoLogo',
   347                  '-NoProfile',
   348                  '-NonInteractive',
   349                  '-ExecutionPolicy',
   350                  'Unrestricted',
   351                  '-Command',
   352                  pwshCommand
   353              ];
   354              core.debug(`Using pwsh at path: ${pwshPath}`);
   355              yield exec_1.exec(`"${pwshPath}"`, args);
   356          }
   357          else {
   358              const powershellCommand = [
   359                  `$ErrorActionPreference = 'Stop' ;`,
   360                  `try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ;`,
   361                  `if ((Get-Command -Name Expand-Archive -Module Microsoft.PowerShell.Archive -ErrorAction Ignore)) { Expand-Archive -LiteralPath '${escapedFile}' -DestinationPath '${escapedDest}' -Force }`,
   362                  `else {[System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}', $true) }`
   363              ].join(' ');
   364              const args = [
   365                  '-NoLogo',
   366                  '-Sta',
   367                  '-NoProfile',
   368                  '-NonInteractive',
   369                  '-ExecutionPolicy',
   370                  'Unrestricted',
   371                  '-Command',
   372                  powershellCommand
   373              ];
   374              const powershellPath = yield io.which('powershell', true);
   375              core.debug(`Using powershell at path: ${powershellPath}`);
   376              yield exec_1.exec(`"${powershellPath}"`, args);
   377          }
   378      });
   379  }
   380  function extractZipNix(file, dest) {
   381      return __awaiter(this, void 0, void 0, function* () {
   382          const unzipPath = yield io.which('unzip', true);
   383          const args = [file];
   384          if (!core.isDebug()) {
   385              args.unshift('-q');
   386          }
   387          args.unshift('-o'); //overwrite with -o, otherwise a prompt is shown which freezes the run
   388          yield exec_1.exec(`"${unzipPath}"`, args, { cwd: dest });
   389      });
   390  }
   391  /**
   392   * Caches a directory and installs it into the tool cacheDir
   393   *
   394   * @param sourceDir    the directory to cache into tools
   395   * @param tool          tool name
   396   * @param version       version of the tool.  semver format
   397   * @param arch          architecture of the tool.  Optional.  Defaults to machine architecture
   398   */
   399  function cacheDir(sourceDir, tool, version, arch) {
   400      return __awaiter(this, void 0, void 0, function* () {
   401          version = semver.clean(version) || version;
   402          arch = arch || os.arch();
   403          core.debug(`Caching tool ${tool} ${version} ${arch}`);
   404          core.debug(`source dir: ${sourceDir}`);
   405          if (!fs.statSync(sourceDir).isDirectory()) {
   406              throw new Error('sourceDir is not a directory');
   407          }
   408          // Create the tool dir
   409          const destPath = yield _createToolPath(tool, version, arch);
   410          // copy each child item. do not move. move can fail on Windows
   411          // due to anti-virus software having an open handle on a file.
   412          for (const itemName of fs.readdirSync(sourceDir)) {
   413              const s = path.join(sourceDir, itemName);
   414              yield io.cp(s, destPath, { recursive: true });
   415          }
   416          // write .complete
   417          _completeToolPath(tool, version, arch);
   418          return destPath;
   419      });
   420  }
   421  exports.cacheDir = cacheDir;
   422  /**
   423   * Caches a downloaded file (GUID) and installs it
   424   * into the tool cache with a given targetName
   425   *
   426   * @param sourceFile    the file to cache into tools.  Typically a result of downloadTool which is a guid.
   427   * @param targetFile    the name of the file name in the tools directory
   428   * @param tool          tool name
   429   * @param version       version of the tool.  semver format
   430   * @param arch          architecture of the tool.  Optional.  Defaults to machine architecture
   431   */
   432  function cacheFile(sourceFile, targetFile, tool, version, arch) {
   433      return __awaiter(this, void 0, void 0, function* () {
   434          version = semver.clean(version) || version;
   435          arch = arch || os.arch();
   436          core.debug(`Caching tool ${tool} ${version} ${arch}`);
   437          core.debug(`source file: ${sourceFile}`);
   438          if (!fs.statSync(sourceFile).isFile()) {
   439              throw new Error('sourceFile is not a file');
   440          }
   441          // create the tool dir
   442          const destFolder = yield _createToolPath(tool, version, arch);
   443          // copy instead of move. move can fail on Windows due to
   444          // anti-virus software having an open handle on a file.
   445          const destPath = path.join(destFolder, targetFile);
   446          core.debug(`destination file ${destPath}`);
   447          yield io.cp(sourceFile, destPath);
   448          // write .complete
   449          _completeToolPath(tool, version, arch);
   450          return destFolder;
   451      });
   452  }
   453  exports.cacheFile = cacheFile;
   454  /**
   455   * Finds the path to a tool version in the local installed tool cache
   456   *
   457   * @param toolName      name of the tool
   458   * @param versionSpec   version of the tool
   459   * @param arch          optional arch.  defaults to arch of computer
   460   */
   461  function find(toolName, versionSpec, arch) {
   462      if (!toolName) {
   463          throw new Error('toolName parameter is required');
   464      }
   465      if (!versionSpec) {
   466          throw new Error('versionSpec parameter is required');
   467      }
   468      arch = arch || os.arch();
   469      // attempt to resolve an explicit version
   470      if (!isExplicitVersion(versionSpec)) {
   471          const localVersions = findAllVersions(toolName, arch);
   472          const match = evaluateVersions(localVersions, versionSpec);
   473          versionSpec = match;
   474      }
   475      // check for the explicit version in the cache
   476      let toolPath = '';
   477      if (versionSpec) {
   478          versionSpec = semver.clean(versionSpec) || '';
   479          const cachePath = path.join(_getCacheDirectory(), toolName, versionSpec, arch);
   480          core.debug(`checking cache: ${cachePath}`);
   481          if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) {
   482              core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`);
   483              toolPath = cachePath;
   484          }
   485          else {
   486              core.debug('not found');
   487          }
   488      }
   489      return toolPath;
   490  }
   491  exports.find = find;
   492  /**
   493   * Finds the paths to all versions of a tool that are installed in the local tool cache
   494   *
   495   * @param toolName  name of the tool
   496   * @param arch      optional arch.  defaults to arch of computer
   497   */
   498  function findAllVersions(toolName, arch) {
   499      const versions = [];
   500      arch = arch || os.arch();
   501      const toolPath = path.join(_getCacheDirectory(), toolName);
   502      if (fs.existsSync(toolPath)) {
   503          const children = fs.readdirSync(toolPath);
   504          for (const child of children) {
   505              if (isExplicitVersion(child)) {
   506                  const fullPath = path.join(toolPath, child, arch || '');
   507                  if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) {
   508                      versions.push(child);
   509                  }
   510              }
   511          }
   512      }
   513      return versions;
   514  }
   515  exports.findAllVersions = findAllVersions;
   516  function getManifestFromRepo(owner, repo, auth, branch = 'master') {
   517      return __awaiter(this, void 0, void 0, function* () {
   518          let releases = [];
   519          const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}`;
   520          const http = new httpm.HttpClient('tool-cache');
   521          const headers = {};
   522          if (auth) {
   523              core.debug('set auth');
   524              headers.authorization = auth;
   525          }
   526          const response = yield http.getJson(treeUrl, headers);
   527          if (!response.result) {
   528              return releases;
   529          }
   530          let manifestUrl = '';
   531          for (const item of response.result.tree) {
   532              if (item.path === 'versions-manifest.json') {
   533                  manifestUrl = item.url;
   534                  break;
   535              }
   536          }
   537          headers['accept'] = 'application/vnd.github.VERSION.raw';
   538          let versionsRaw = yield (yield http.get(manifestUrl, headers)).readBody();
   539          if (versionsRaw) {
   540              // shouldn't be needed but protects against invalid json saved with BOM
   541              versionsRaw = versionsRaw.replace(/^\uFEFF/, '');
   542              try {
   543                  releases = JSON.parse(versionsRaw);
   544              }
   545              catch (_a) {
   546                  core.debug('Invalid json');
   547              }
   548          }
   549          return releases;
   550      });
   551  }
   552  exports.getManifestFromRepo = getManifestFromRepo;
   553  function findFromManifest(versionSpec, stable, manifest, archFilter = os.arch()) {
   554      return __awaiter(this, void 0, void 0, function* () {
   555          // wrap the internal impl
   556          const match = yield mm._findMatch(versionSpec, stable, manifest, archFilter);
   557          return match;
   558      });
   559  }
   560  exports.findFromManifest = findFromManifest;
   561  function _createExtractFolder(dest) {
   562      return __awaiter(this, void 0, void 0, function* () {
   563          if (!dest) {
   564              // create a temp dir
   565              dest = path.join(_getTempDirectory(), v4_1.default());
   566          }
   567          yield io.mkdirP(dest);
   568          return dest;
   569      });
   570  }
   571  function _createToolPath(tool, version, arch) {
   572      return __awaiter(this, void 0, void 0, function* () {
   573          const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || '');
   574          core.debug(`destination ${folderPath}`);
   575          const markerPath = `${folderPath}.complete`;
   576          yield io.rmRF(folderPath);
   577          yield io.rmRF(markerPath);
   578          yield io.mkdirP(folderPath);
   579          return folderPath;
   580      });
   581  }
   582  function _completeToolPath(tool, version, arch) {
   583      const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || '');
   584      const markerPath = `${folderPath}.complete`;
   585      fs.writeFileSync(markerPath, '');
   586      core.debug('finished caching tool');
   587  }
   588  /**
   589   * Check if version string is explicit
   590   *
   591   * @param versionSpec      version string to check
   592   */
   593  function isExplicitVersion(versionSpec) {
   594      const c = semver.clean(versionSpec) || '';
   595      core.debug(`isExplicit: ${c}`);
   596      const valid = semver.valid(c) != null;
   597      core.debug(`explicit? ${valid}`);
   598      return valid;
   599  }
   600  exports.isExplicitVersion = isExplicitVersion;
   601  /**
   602   * Get the highest satisfiying semantic version in `versions` which satisfies `versionSpec`
   603   *
   604   * @param versions        array of versions to evaluate
   605   * @param versionSpec     semantic version spec to satisfy
   606   */
   607  function evaluateVersions(versions, versionSpec) {
   608      let version = '';
   609      core.debug(`evaluating ${versions.length} versions`);
   610      versions = versions.sort((a, b) => {
   611          if (semver.gt(a, b)) {
   612              return 1;
   613          }
   614          return -1;
   615      });
   616      for (let i = versions.length - 1; i >= 0; i--) {
   617          const potential = versions[i];
   618          const satisfied = semver.satisfies(potential, versionSpec);
   619          if (satisfied) {
   620              version = potential;
   621              break;
   622          }
   623      }
   624      if (version) {
   625          core.debug(`matched: ${version}`);
   626      }
   627      else {
   628          core.debug('match not found');
   629      }
   630      return version;
   631  }
   632  exports.evaluateVersions = evaluateVersions;
   633  /**
   634   * Gets RUNNER_TOOL_CACHE
   635   */
   636  function _getCacheDirectory() {
   637      const cacheDirectory = process.env['RUNNER_TOOL_CACHE'] || '';
   638      assert_1.ok(cacheDirectory, 'Expected RUNNER_TOOL_CACHE to be defined');
   639      return cacheDirectory;
   640  }
   641  /**
   642   * Gets RUNNER_TEMP
   643   */
   644  function _getTempDirectory() {
   645      const tempDirectory = process.env['RUNNER_TEMP'] || '';
   646      assert_1.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
   647      return tempDirectory;
   648  }
   649  /**
   650   * Gets a global variable
   651   */
   652  function _getGlobal(key, defaultValue) {
   653      /* eslint-disable @typescript-eslint/no-explicit-any */
   654      const value = global[key];
   655      /* eslint-enable @typescript-eslint/no-explicit-any */
   656      return value !== undefined ? value : defaultValue;
   657  }
   658  /**
   659   * Returns an array of unique values.
   660   * @param values Values to make unique.
   661   */
   662  function _unique(values) {
   663      return Array.from(new Set(values));
   664  }
   665  //# sourceMappingURL=tool-cache.js.map