"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateInstallCommands = exports.resolveConstraint = exports.isDynamicInstall = exports.isContainerbase = exports.supportsDynamicInstall = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const shlex_1 = require("shlex");
const global_1 = require("../../config/global");
const logger_1 = require("../../logger");
const datasource_1 = require("../../modules/datasource");
const allVersioning = tslib_1.__importStar(require("../../modules/versioning"));
const composer_1 = require("../../modules/versioning/composer");
const gradle_1 = require("../../modules/versioning/gradle");
const maven_1 = require("../../modules/versioning/maven");
const node_1 = require("../../modules/versioning/node");
const npm_1 = require("../../modules/versioning/npm");
const pep440_1 = require("../../modules/versioning/pep440");
const python_1 = require("../../modules/versioning/python");
const ruby_1 = require("../../modules/versioning/ruby");
const semver_1 = require("../../modules/versioning/semver");
const semver_coerced_1 = require("../../modules/versioning/semver-coerced");
const allToolConfig = {
    bundler: {
        datasource: 'rubygems',
        packageName: 'bundler',
        versioning: ruby_1.id,
    },
    cocoapods: {
        datasource: 'rubygems',
        packageName: 'cocoapods',
        versioning: ruby_1.id,
    },
    composer: {
        datasource: 'github-releases',
        packageName: 'composer/composer',
        versioning: composer_1.id,
    },
    corepack: {
        datasource: 'npm',
        packageName: 'corepack',
        versioning: npm_1.id,
    },
    dotnet: {
        datasource: 'dotnet-version',
        packageName: 'dotnet-sdk',
        versioning: semver_1.id,
    },
    erlang: {
        datasource: 'github-releases',
        packageName: 'containerbase/erlang-prebuild',
        versioning: semver_coerced_1.id,
    },
    elixir: {
        datasource: 'github-releases',
        packageName: 'elixir-lang/elixir',
        versioning: semver_1.id,
    },
    flux: {
        datasource: 'github-releases',
        packageName: 'fluxcd/flux2',
        versioning: semver_1.id,
    },
    golang: {
        datasource: 'golang-version',
        packageName: 'golang',
        versioning: npm_1.id,
    },
    gradle: {
        datasource: 'gradle-version',
        packageName: 'gradle',
        versioning: gradle_1.id,
    },
    hashin: {
        datasource: 'pypi',
        packageName: 'hashin',
        versioning: pep440_1.id,
    },
    helm: {
        datasource: 'github-releases',
        packageName: 'helm/helm',
        versioning: semver_1.id,
    },
    helmfile: {
        datasource: 'github-releases',
        packageName: 'helmfile/helmfile',
        versioning: semver_1.id,
    },
    java: {
        datasource: 'java-version',
        packageName: 'java',
        versioning: npm_1.id,
    },
    /* not used in Renovate */
    'java-maven': {
        datasource: 'java-version',
        packageName: 'java',
        versioning: maven_1.id,
    },
    jb: {
        datasource: 'github-releases',
        packageName: 'jsonnet-bundler/jsonnet-bundler',
        versioning: semver_1.id,
    },
    kustomize: {
        datasource: 'github-releases',
        packageName: 'kubernetes-sigs/kustomize',
        extractVersion: '^kustomize/v(?<version>.*)$',
        versioning: semver_1.id,
    },
    lerna: {
        datasource: 'npm',
        packageName: 'lerna',
        versioning: npm_1.id,
    },
    maven: {
        datasource: 'maven',
        packageName: 'org.apache.maven:maven',
        versioning: maven_1.id,
    },
    nix: {
        datasource: 'github-tags',
        packageName: 'NixOS/nix',
        versioning: semver_1.id,
    },
    node: {
        datasource: 'node-version',
        packageName: 'node',
        versioning: node_1.id,
    },
    npm: {
        datasource: 'npm',
        packageName: 'npm',
        hash: true,
        versioning: npm_1.id,
    },
    pdm: {
        datasource: 'github-releases',
        packageName: 'pdm-project/pdm',
        versioning: semver_1.id,
    },
    php: {
        datasource: 'github-releases',
        packageName: 'containerbase/php-prebuild',
        versioning: composer_1.id,
    },
    'pip-tools': {
        datasource: 'pypi',
        packageName: 'pip-tools',
        versioning: pep440_1.id,
    },
    pipenv: {
        datasource: 'pypi',
        packageName: 'pipenv',
        versioning: pep440_1.id,
    },
    pnpm: {
        datasource: 'npm',
        packageName: 'pnpm',
        versioning: npm_1.id,
    },
    poetry: {
        datasource: 'pypi',
        packageName: 'poetry',
        versioning: pep440_1.id,
    },
    python: {
        datasource: 'github-releases',
        packageName: 'containerbase/python-prebuild',
        versioning: python_1.id,
    },
    ruby: {
        datasource: 'github-releases',
        packageName: 'containerbase/ruby-prebuild',
        versioning: ruby_1.id,
    },
    rust: {
        datasource: 'docker',
        packageName: 'rust',
        versioning: semver_1.id,
    },
    yarn: {
        datasource: 'npm',
        packageName: 'yarn',
        versioning: npm_1.id,
    },
    'yarn-slim': {
        datasource: 'npm',
        packageName: 'yarn',
        versioning: npm_1.id,
    },
    dart: {
        datasource: 'dart-version',
        packageName: 'dart',
        versioning: semver_1.id,
    },
    flutter: {
        datasource: 'flutter-version',
        packageName: 'flutter',
        versioning: semver_1.id,
    },
};
function supportsDynamicInstall(toolName) {
    return !!allToolConfig[toolName];
}
exports.supportsDynamicInstall = supportsDynamicInstall;
function isContainerbase() {
    return !!process.env.CONTAINERBASE || !!process.env.BUILDPACK;
}
exports.isContainerbase = isContainerbase;
function isDynamicInstall(toolConstraints) {
    if (global_1.GlobalConfig.get('binarySource') !== 'install') {
        return false;
    }
    if (!isContainerbase()) {
        logger_1.logger.debug('Falling back to binarySource=global');
        return false;
    }
    return (!toolConstraints ||
        toolConstraints.every((toolConstraint) => supportsDynamicInstall(toolConstraint.toolName)));
}
exports.isDynamicInstall = isDynamicInstall;
function isStable(version, versioning, latest) {
    if (!versioning.isStable(version)) {
        return false;
    }
    if (is_1.default.string(latest)) {
        if (versioning.isGreaterThan(version, latest)) {
            return false;
        }
    }
    return true;
}
async function resolveConstraint(toolConstraint) {
    const { toolName } = toolConstraint;
    const toolConfig = allToolConfig[toolName];
    if (!toolConfig) {
        throw new Error(`Invalid tool to install: ${toolName}`);
    }
    const versioning = allVersioning.get(toolConfig.versioning);
    let constraint = toolConstraint.constraint;
    if (constraint) {
        if (versioning.isValid(constraint)) {
            if (versioning.isSingleVersion(constraint)) {
                return constraint.replace(/^=+/, '').trim();
            }
        }
        else {
            logger_1.logger.warn({ toolName, constraint, versioning: toolConfig.versioning }, 'Invalid tool constraint');
            constraint = undefined;
        }
    }
    const pkgReleases = await (0, datasource_1.getPkgReleases)(toolConfig);
    const releases = pkgReleases?.releases ?? [];
    if (!releases?.length) {
        logger_1.logger.warn({ toolConfig }, 'No tool releases found.');
        throw new Error('No tool releases found.');
    }
    const matchingReleases = releases.filter((r) => !constraint || versioning.matches(r.version, constraint));
    const stableMatchingVersion = matchingReleases
        .filter((r) => isStable(r.version, versioning, pkgReleases?.tags?.latest))
        .pop()?.version;
    if (stableMatchingVersion) {
        logger_1.logger.debug({ toolName, constraint, resolvedVersion: stableMatchingVersion }, 'Resolved stable matching version');
        return stableMatchingVersion;
    }
    const unstableMatchingVersion = matchingReleases.pop()?.version;
    if (unstableMatchingVersion) {
        logger_1.logger.debug({ toolName, constraint, resolvedVersion: unstableMatchingVersion }, 'Resolved unstable matching version');
        return unstableMatchingVersion;
    }
    const stableVersion = releases
        .filter((r) => isStable(r.version, versioning, pkgReleases?.tags?.latest))
        .pop()?.version;
    if (stableVersion) {
        logger_1.logger.warn({ toolName, constraint, stableVersion }, 'No matching tool versions found for constraint - using latest stable version');
    }
    const highestVersion = releases.pop().version;
    logger_1.logger.warn({ toolName, constraint, highestVersion }, 'No matching or stable tool versions found - using an unstable version');
    return highestVersion;
}
exports.resolveConstraint = resolveConstraint;
async function generateInstallCommands(toolConstraints) {
    const installCommands = [];
    if (toolConstraints?.length) {
        for (const toolConstraint of toolConstraints) {
            const toolVersion = await resolveConstraint(toolConstraint);
            const { toolName } = toolConstraint;
            const installCommand = `install-tool ${toolName} ${(0, shlex_1.quote)(toolVersion)}`;
            installCommands.push(installCommand);
            if (allToolConfig[toolName].hash) {
                installCommands.push(`hash -d ${toolName} 2>/dev/null || true`);
            }
        }
    }
    return installCommands;
}
exports.generateInstallCommands = generateInstallCommands;
//# sourceMappingURL=containerbase.js.map