"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateDependency = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const hasha_1 = tslib_1.__importDefault(require("hasha"));
const logger_1 = require("../../../logger");
const packageCache = tslib_1.__importStar(require("../../../util/cache/package"));
const http_1 = require("../../../util/http");
const promises_1 = require("../../../util/promises");
const regex_1 = require("../../../util/regex");
const common_1 = require("./common");
const http = new http_1.Http('bazel');
function getUrlFragments(rule) {
    const urls = [];
    const urlRecord = rule.children['url'];
    if (urlRecord?.type === 'string') {
        urls.push(urlRecord);
    }
    const urlsRecord = rule.children['urls'];
    if (urlsRecord?.type === 'array') {
        for (const urlRecord of urlsRecord.children) {
            if (urlRecord.type === 'string') {
                urls.push(urlRecord);
            }
        }
    }
    return urls;
}
const urlMassages = {
    'bazel-skylib.': 'bazel_skylib-',
    '/bazel-gazelle/releases/download/0': '/bazel-gazelle/releases/download/v0',
    '/bazel-gazelle-0': '/bazel-gazelle-v0',
    '/rules_go/releases/download/0': '/rules_go/releases/download/v0',
    '/rules_go-0': '/rules_go-v0',
};
function massageUrl(url) {
    let result = url;
    for (const [from, to] of Object.entries(urlMassages)) {
        result = result.replace(from, to);
    }
    return result;
}
function replaceAll(input, from, to) {
    return input.split(from).join(to);
}
function replaceValues(content, from, to) {
    // istanbul ignore if
    if (!from || !to || from === to) {
        return content;
    }
    const massagedFrom = from.replace((0, regex_1.regEx)(/^v/), '');
    const massagedTo = to.replace((0, regex_1.regEx)(/^v/), '');
    return replaceAll(content, massagedFrom, massagedTo);
}
async function getHashFromUrl(url) {
    const cacheNamespace = 'url-sha256';
    const cachedResult = await packageCache.get(cacheNamespace, url);
    /* istanbul ignore next line */
    if (cachedResult) {
        return cachedResult;
    }
    try {
        const hash = await hasha_1.default.fromStream(http.stream(url), {
            algorithm: 'sha256',
        });
        const cacheMinutes = 3 * 24 * 60; // 3 days
        await packageCache.set(cacheNamespace, url, hash, cacheMinutes);
        return hash;
    }
    catch (err) /* istanbul ignore next */ {
        return null;
    }
}
async function getHashFromUrls(urls) {
    const hashes = (await (0, promises_1.map)(urls, (url) => getHashFromUrl(massageUrl(url)))).filter(is_1.default.truthy);
    if (!hashes.length) {
        logger_1.logger.debug({ urls }, 'Could not calculate hash for URLs');
        return null;
    }
    const distinctHashes = new Set(hashes);
    // istanbul ignore if
    if (distinctHashes.size > 1) {
        logger_1.logger.warn({ urls }, 'Found multiple hashes for single def');
    }
    return hashes[0];
}
async function updateDependency({ fileContent, upgrade, }) {
    try {
        const { newValue, newDigest } = upgrade;
        logger_1.logger.debug({ newValue, newDigest }, `bazel.updateDependency()`);
        const idx = upgrade.managerData.idx;
        if (upgrade.depType === 'container_pull') {
            let result = fileContent;
            if (newValue) {
                result = (0, common_1.updateCode)(result, [idx, 'tag'], newValue);
            }
            if (newDigest) {
                result = (0, common_1.updateCode)(result, [idx, 'digest'], newDigest);
            }
            return result;
        }
        if (upgrade.depType === 'git_repository' ||
            upgrade.depType === 'go_repository') {
            let result = fileContent;
            if (newValue) {
                result = (0, common_1.updateCode)(result, [idx, 'tag'], newValue);
            }
            if (newDigest) {
                result = (0, common_1.updateCode)(result, [idx, 'commit'], newDigest);
            }
            return result;
        }
        if (upgrade.depType === 'http_file' || upgrade.depType === 'http_archive') {
            const rule = (0, common_1.findCodeFragment)(fileContent, [idx]);
            // istanbul ignore if
            if (rule?.type !== 'record') {
                return null;
            }
            const urlFragments = getUrlFragments(rule);
            if (!urlFragments?.length) {
                logger_1.logger.debug(`def: ${rule.value}, urls is empty`);
                return null;
            }
            const updateValues = (oldUrl) => {
                let url = oldUrl;
                url = replaceValues(url, upgrade.currentValue, upgrade.newValue);
                url = replaceValues(url, upgrade.currentDigest, upgrade.newDigest);
                return url;
            };
            const urls = urlFragments.map(({ value }) => updateValues(value));
            const hash = await getHashFromUrls(urls);
            if (!hash) {
                return null;
            }
            let result = fileContent;
            result = (0, common_1.patchCodeAtFragments)(result, urlFragments, updateValues);
            result = (0, common_1.updateCode)(result, [idx, 'strip_prefix'], updateValues);
            result = (0, common_1.updateCode)(result, [idx, 'sha256'], hash);
            return result;
        }
    }
    catch (err) /* istanbul ignore next */ {
        logger_1.logger.debug({ err }, 'Error setting new bazel WORKSPACE version');
    }
    // istanbul ignore next
    return null;
}
exports.updateDependency = updateDependency;
//# sourceMappingURL=update.js.map