"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 pnpm_logger_1 = require("pnpm-logger");
const fs = require("mz/fs");
const path = require("path");
const spawn = require("cross-spawn");
const execa = require("execa");
const unpackStream = require("unpack-stream");
const existsFile = require("path-exists");
const logInstallStatus_1 = require("../logging/logInstallStatus");
const parse_npm_tarball_url_1 = require("parse-npm-tarball-url");
const parse_codeload_url_1 = require("parse-codeload-url");
const getRegistryName_1 = require("../resolve/npm/getRegistryName");
const errorTypes_1 = require("../errorTypes");
const gitLogger = pnpm_logger_1.default('git');
const fetchLogger = pnpm_logger_1.default('fetch');
function fetchResolution(resolution, target, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        switch (resolution.type) {
            case undefined:
                const dist = {
                    tarball: resolution.tarball,
                    shasum: resolution.shasum,
                };
                yield fetchFromTarball(target, dist, opts);
                break;
            case 'git-repo':
                yield clone(resolution.repo, resolution.commitId, target);
                break;
            case 'directory': {
                const tgzFilename = yield npmPack(resolution.root);
                const tarball = path.resolve(resolution.root, tgzFilename);
                const dist = { tarball: tarball };
                yield fetchFromLocalTarball(target, dist);
                yield fs.unlink(dist.tarball);
                break;
            }
        }
    });
}
exports.default = fetchResolution;
function npmPack(dependencyPath) {
    return new Promise((resolve, reject) => {
        const proc = spawn('npm', ['pack'], {
            cwd: dependencyPath
        });
        let stdout = '';
        proc.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        proc.on('error', reject);
        proc.on('close', (code) => {
            if (code > 0)
                return reject(new Error('Exit code ' + code));
            const tgzFilename = stdout.trim();
            return resolve(tgzFilename);
        });
    });
}
/**
 * clone a git repository.
 */
function clone(repo, commitId, dest) {
    return __awaiter(this, void 0, void 0, function* () {
        yield execGit(['clone', repo, dest]);
        yield execGit(['checkout', commitId], { cwd: dest });
    });
}
function prefixGitArgs() {
    return process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : [];
}
function execGit(args, opts) {
    gitLogger.debug(`executing git with args ${args}`);
    const fullArgs = prefixGitArgs().concat(args || []);
    return execa('git', fullArgs, opts);
}
function fetchFromTarball(dir, dist, opts) {
    if (dist.tarball.startsWith('file:')) {
        dist = Object.assign({}, dist, { tarball: dist.tarball.slice(5) });
        return fetchFromLocalTarball(dir, dist);
    }
    else {
        return fetchFromRemoteTarball(dir, dist, opts);
    }
}
exports.fetchFromTarball = fetchFromTarball;
function fetchFromRemoteTarball(dir, dist, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const localTarballPath = getLocalTarballPath(dist.tarball, opts.localRegistry);
        if (!(yield existsFile(localTarballPath))) {
            if (opts.offline) {
                throw new errorTypes_1.PnpmError('NO_OFFLINE_TARBALL', `Could not find ${localTarballPath} in local registry mirror ${opts.localRegistry}`);
            }
            yield opts.got.download(dist.tarball, localTarballPath, {
                shasum: dist.shasum,
                onStart: () => logInstallStatus_1.default({ status: 'fetching', pkgId: opts.pkgId }),
                onProgress: (done, total) => logInstallStatus_1.default({
                    status: 'fetching',
                    pkgId: opts.pkgId,
                    progress: { done, total },
                })
            });
        }
        yield fetchFromLocalTarball(dir, {
            shasum: dist.shasum,
            tarball: localTarballPath,
        });
        fetchLogger.debug(`finish ${dist.shasum} ${dist.tarball}`);
    });
}
exports.fetchFromRemoteTarball = fetchFromRemoteTarball;
function getLocalTarballPath(tarballUrl, localRegistry) {
    const tarball = parse_npm_tarball_url_1.default(tarballUrl);
    if (tarball) {
        const escapedHost = getRegistryName_1.escapeHost(tarball.host);
        return path.join(localRegistry, escapedHost, tarball.pkg.name, `${unscope(tarball.pkg.name)}-${tarball.pkg.version}.tgz`);
    }
    if (tarballUrl.includes('//codeload.github.com')) {
        const repo = parse_codeload_url_1.default(tarballUrl);
        return path.join(localRegistry, 'codeload.github.com', repo.owner, repo.name, `${repo.name}-${repo.commit}.tgz`);
    }
    return path.join(localRegistry, normalizeTarballExtension(tarballUrl.replace(/^.*:\/\/(git@)?/, '')));
}
function normalizeTarballExtension(tarballUrl) {
    if (tarballUrl.endsWith('.tar.gz')) {
        return `${tarballUrl.slice(0, -7)}.tgz`;
    }
    if (tarballUrl.endsWith('.tgz')) {
        return tarballUrl;
    }
    return `${tarballUrl}.tgz`;
}
function unscope(pkgName) {
    if (pkgName[0] === '@') {
        return pkgName.split('/')[1];
    }
    return pkgName;
}
function fetchFromLocalTarball(dir, dist) {
    return __awaiter(this, void 0, void 0, function* () {
        yield unpackStream.local(fs.createReadStream(dist.tarball), dir);
    });
}
//# sourceMappingURL=fetchResolution.js.map