"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 logInstallStatus_1 = require("../logging/logInstallStatus");
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 'tarball':
                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 stream = yield opts.got.getStream(dist.tarball);
        yield unpackStream.remote(stream, dir, {
            shasum: dist.shasum,
            onStart: () => logInstallStatus_1.default({ status: 'download-start', pkg: opts.loggedPkg }),
            onProgress: (done, total) => logInstallStatus_1.default({ status: 'downloading', pkg: opts.loggedPkg, downloadStatus: { done, total } })
        });
        fetchLogger.debug(`finish ${dist.shasum} ${dist.tarball}`);
    });
}
exports.fetchFromRemoteTarball = fetchFromRemoteTarball;
function fetchFromLocalTarball(dir, dist) {
    return __awaiter(this, void 0, void 0, function* () {
        yield unpackStream.local(fs.createReadStream(dist.tarball), dir);
    });
}
exports.fetchFromLocalTarball = fetchFromLocalTarball;
//# sourceMappingURL=fetchResolution.js.map