"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HermitDatasource = void 0;
const tslib_1 = require("tslib");
const logger_1 = require("../../../logger");
const decorator_1 = require("../../../util/cache/package/decorator");
const url_1 = require("../../../util/github/url");
const github_1 = require("../../../util/http/github");
const regex_1 = require("../../../util/regex");
const streams_1 = require("../../../util/streams");
const url_2 = require("../../../util/url");
const hermit_1 = require("../../versioning/hermit");
const datasource_1 = require("../datasource");
/**
 * Hermit Datasource searches a given package from the specified `hermit-packages`
 * repository. It expects the search manifest to come from an asset `index.json` from
 * a release named index.
 */
class HermitDatasource extends datasource_1.Datasource {
    constructor() {
        super(HermitDatasource.id);
        this.customRegistrySupport = true;
        this.registryStrategy = 'first';
        this.defaultVersioning = hermit_1.id;
        this.defaultRegistryUrls = [
            'https://github.com/cashapp/hermit-packages',
        ];
        this.http = new github_1.GithubHttp(hermit_1.id);
        this.pathRegex = (0, regex_1.regEx)('^\\/(?<owner>[^/]+)\\/(?<repo>[^/]+)$');
    }
    async getReleases({ packageName, registryUrl, }) {
        logger_1.logger.trace(`HermitDataSource.getReleases()`);
        if (!registryUrl) {
            logger_1.logger.error('registryUrl must be supplied');
            return null;
        }
        const parsedUrl = (0, url_2.parseUrl)(registryUrl);
        if (parsedUrl === null) {
            logger_1.logger.warn({ registryUrl }, 'invalid registryUrl given');
            return null;
        }
        if (!registryUrl.startsWith('https://github.com/')) {
            logger_1.logger.warn({ registryUrl }, 'Only Github registryUrl is supported');
            return null;
        }
        const items = await this.getHermitSearchManifest(parsedUrl);
        if (items === null) {
            return null;
        }
        const res = items.find((i) => i.Name === packageName);
        if (!res) {
            logger_1.logger.debug({ packageName, registryUrl }, 'cannot find hermit package');
            return null;
        }
        const sourceUrl = res.Repository;
        return {
            sourceUrl,
            releases: [
                ...res.Versions.map((v) => ({
                    version: v,
                    sourceUrl,
                })),
                ...res.Channels.map((v) => ({
                    version: v,
                    sourceUrl,
                })),
            ],
        };
    }
    /**
     * getHermitSearchManifest fetch the index.json from release
     * named index, parses it and returned the parsed JSON result
     */
    async getHermitSearchManifest(u) {
        const registryUrl = u.toString();
        const host = u.host ?? '';
        const groups = this.pathRegex.exec(u.pathname ?? '')?.groups;
        if (!groups) {
            logger_1.logger.warn({ registryUrl }, 'failed to get owner and repo from given url');
            return null;
        }
        const { owner, repo } = groups;
        const apiBaseUrl = (0, url_1.getApiBaseUrl)(`https://${host}`);
        const indexRelease = await this.http.getJson(`${apiBaseUrl}repos/${owner}/${repo}/releases/tags/index`);
        // finds asset with name index.json
        const asset = indexRelease.body.assets.find((asset) => asset.name === 'index.json');
        if (!asset) {
            logger_1.logger.warn({ registryUrl }, `can't find asset index.json in the given registryUrl`);
            return null;
        }
        // stream down the content of index.json
        // Note: need to use stream here with
        // the accept header as octet-stream to
        // download asset from private github repository
        // see GithubDoc:
        // https://docs.github.com/en/rest/releases/assets#get-a-release-asset
        const indexContent = await (0, streams_1.streamToString)(this.http.stream(asset.url, {
            headers: {
                accept: 'application/octet-stream',
            },
        }));
        try {
            return JSON.parse(indexContent);
        }
        catch (e) {
            logger_1.logger.warn('error parsing hermit search manifest from remote respond');
        }
        return null;
    }
}
HermitDatasource.id = 'hermit';
tslib_1.__decorate([
    (0, decorator_1.cache)({
        namespace: `datasource-hermit-package`,
        key: ({ registryUrl, packageName }) => `${registryUrl ?? ''}-${packageName}`,
    })
], HermitDatasource.prototype, "getReleases", null);
tslib_1.__decorate([
    (0, decorator_1.cache)({
        namespace: `datasource-hermit-search-manifest`,
        key: (u) => u.toString(),
    })
], HermitDatasource.prototype, "getHermitSearchManifest", null);
exports.HermitDatasource = HermitDatasource;
//# sourceMappingURL=index.js.map