"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const execa = require("execa");
const hostedGitInfo = require("@zkochan/hosted-git-info");
const pnpm_logger_1 = require("pnpm-logger");
const normalizeSsh = require("normalize-ssh");
const gitLogger = pnpm_logger_1.default('git-logger');
let tryGitHubApi = true;
function resolveGit(parsedSpec, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const hspec = parsedSpec;
        const isGitHubHosted = parsedSpec.type === 'hosted' && hspec.hosted.type === 'github';
        const parts = normalizeRepoUrl(parsedSpec.spec).split('#');
        const repo = parts[0];
        const ref = parts[1] || 'master';
        if (!isGitHubHosted || isSsh(parsedSpec.spec)) {
            const commitId = yield resolveRef(repo, ref);
            const resolution = {
                type: 'git-repo',
                repo,
                commitId,
            };
            return {
                id: repo
                    .replace(/^.*:\/\/(git@)?/, '')
                    .replace(/:/g, '+')
                    .replace(/\.git$/, '') + '/' + commitId,
                resolution,
            };
        }
        const ghSpec = parseGithubSpec(hspec);
        let commitId;
        if (tryGitHubApi) {
            try {
                commitId = yield tryResolveViaGitHubApi(ghSpec, opts.got);
            }
            catch (err) {
                gitLogger.warn({
                    message: `Error while trying to resolve ${parsedSpec.spec} via GitHub API`,
                    err,
                });
                // if it fails once, don't bother retrying for other packages
                tryGitHubApi = false;
                commitId = yield resolveRef(repo, ref);
            }
        }
        else {
            commitId = yield resolveRef(repo, ref);
        }
        const resolution = {
            type: 'tarball',
            tarball: `https://codeload.github.com/${ghSpec.owner}/${ghSpec.repo}/tar.gz/${commitId}`,
        };
        return {
            id: ['github.com', ghSpec.owner, ghSpec.repo, commitId].join('/'),
            resolution,
        };
    });
}
exports.default = resolveGit;
function resolveRef(repo, ref) {
    return __awaiter(this, void 0, void 0, function* () {
        const result = yield execa('git', ['ls-remote', '--refs', repo, ref]);
        // should output something like:
        //   572bc3d4e16220c2e986091249e62a5913294b25    	refs/heads/master
        // if no ref was found, assume that ref is the commit ID
        if (!result.stdout)
            return ref;
        return result.stdout.match(/^[a-z0-9]+/)[0];
    });
}
function normalizeRepoUrl(repoUrl) {
    const hosted = hostedGitInfo.fromUrl(repoUrl);
    if (!hosted)
        return normalizeSsh(repoUrl);
    return hosted.getDefaultRepresentation() == 'shortcut' ? hosted.git() : hosted.toString();
}
function isSsh(gitSpec) {
    return gitSpec.substr(0, 10) === 'git+ssh://'
        || gitSpec.substr(0, 4) === 'git@';
}
/**
 * Resolves a 'hosted' package hosted on 'github'.
 */
function tryResolveViaGitHubApi(spec, got) {
    return __awaiter(this, void 0, void 0, function* () {
        const url = [
            'https://api.github.com/repos',
            spec.owner,
            spec.repo,
            'commits',
            spec.ref
        ].join('/');
        const body = yield got.getJSON(url);
        return body.sha;
    });
}
const PARSE_GITHUB_RE = /^github:([^\/]+)\/([^#]+)(#(.+))?$/;
function parseGithubSpec(spec) {
    const m = PARSE_GITHUB_RE.exec(spec.hosted.shortcut);
    if (!m) {
        throw new Error('cannot parse: ' + spec.hosted.shortcut);
    }
    const owner = m[1];
    const repo = m[2];
    const ref = m[4] || 'HEAD';
    return { owner, repo, ref };
}
//# sourceMappingURL=git.js.map