"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());
    });
};
const readPkgUp = require('read-pkg-up');
const path = require('path');
const semver = require('semver');
const common_tags_1 = require('common-tags');
const requireJson_1 = require('../fs/requireJson');
const writePkg = require('write-pkg');
const expandTilde_1 = require('../fs/expandTilde');
const logger_1 = require('../logger');
const storeController_1 = require('../fs/storeController');
const modulesController_1 = require('../fs/modulesController');
const mkdirp_1 = require('../fs/mkdirp');
const cache_1 = require('./cache');
const normalizePath = require('normalize-path');
const env_1 = require('../env');
const constantDefaults_1 = require('./constantDefaults');
function default_1(opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const pkg = yield (opts.global ? readGlobalPkg(opts.globalPath) : readPkgUp({ cwd: opts.cwd }));
        const root = normalizePath(pkg.path ? path.dirname(pkg.path) : opts.cwd);
        const storeBasePath = resolveStoreBasePath(opts.storePath, root);
        // to avoid orphan packages created with pnpm v0.41.0 and earlier
        if (!underNodeModules(storeBasePath) && (yield storeController_1.read(storeBasePath))) {
            throw new Error(structureChangeMsg('Shared stores were divided into types, flat and nested. https://github.com/rstacruz/pnpm/pull/429'));
        }
        const treeType = opts.flatTree ? 'flat' : 'nested';
        const storePath = getStorePath(treeType, storeBasePath);
        let modules = yield modulesController_1.read(path.join(root, 'node_modules'));
        const isFirstInstallation = !modules;
        if (modules && modules.storePath !== storePath) {
            const err = new Error(`The package's modules are from store at ${modules.storePath} and you are trying to use store at ${storePath}`);
            err['code'] = 'ALIEN_STORE';
            throw err;
        }
        const store = (yield storeController_1.read(storePath)) || storeController_1.create(treeType);
        store.type = store.type || 'nested'; // for backward compatibility with v0.41.0 and earlier
        if (store.type !== treeType) {
            const err = new Error(`Cannot use a ${store.type} store for a ${treeType} installation`);
            err['code'] = 'INCONSISTENT_TREE_TYPE';
            throw err;
        }
        if (store.preserveSymlinks !== env_1.preserveSymlinks) {
            const err = new Error(`Cannot use a store installed with preserveSymlinks = ${store.preserveSymlinks}. Need store with preserveSymlinks = ${env_1.preserveSymlinks}`);
            err['code'] = 'INCONSISTENT_PRESERVE_SYMLINKS';
            throw err;
        }
        if (store) {
            failIfNotCompatible(store.pnpm);
        }
        const ctx = {
            pkg: pkg.pkg,
            root,
            cache: cache_1.getCachePath(opts.globalPath),
            storePath,
            store,
            isFirstInstallation,
        };
        if (!opts.silent)
            logger_1.default(opts.logger);
        yield mkdirp_1.default(ctx.cache);
        yield mkdirp_1.default(ctx.storePath);
        return ctx;
    });
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
function failIfNotCompatible(storeVersion) {
    if (!storeVersion || !semver.satisfies(storeVersion, '>=0.28')) {
        const msg = structureChangeMsg('More info about what was changed at: https://github.com/rstacruz/pnpm/issues/276');
        throw new Error(msg);
    }
    if (!semver.satisfies(storeVersion, '>=0.33')) {
        const msg = structureChangeMsg(common_tags_1.stripIndent `
      The change was needed to fix the GitHub rate limit issue:
        Issue: https://github.com/rstacruz/pnpm/issues/361
        PR: https://github.com/rstacruz/pnpm/pull/363
    `);
        throw new Error(msg);
    }
    if (!semver.satisfies(storeVersion, '>=0.37')) {
        const msg = structureChangeMsg(common_tags_1.stripIndent `
      The structure of store.json/dependencies was changed to map dependencies to their fullnames
    `);
        throw new Error(msg);
    }
    if (!semver.satisfies(storeVersion, '>=0.38')) {
        const msg = structureChangeMsg(common_tags_1.stripIndent `
      The structure of store.json/dependencies was changed to not include the redundunt package.json at the end
    `);
        throw new Error(msg);
    }
}
function structureChangeMsg(moreInfo) {
    return common_tags_1.stripIndent `
    The store structure was changed.
    Remove it and run pnpm again.
    ${moreInfo}
    TIPS:
      If you have a shared store, remove both the node_modules and the shared store.
      Otherwise just run \`rm -rf node_modules\`
  `;
}
function readGlobalPkg(globalPath) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!globalPath)
            throw new Error('globalPath is required');
        const globalPnpm = expandTilde_1.default(globalPath);
        const globalPkgPath = path.resolve(globalPnpm, 'package.json');
        const globalPkgJson = yield readGlobalPkgJson(globalPkgPath);
        return {
            pkg: globalPkgJson,
            path: globalPkgPath
        };
    });
}
const DefaultGlobalPkg = {
    name: 'pnpm-global-pkg',
    version: '1.0.0',
    private: true,
    config: {
        npm: {
            storePath: constantDefaults_1.GlobalStorePath
        }
    }
};
function readGlobalPkgJson(globalPkgPath) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const globalPkgJson = yield requireJson_1.default(globalPkgPath);
            return globalPkgJson;
        }
        catch (err) {
            yield mkdirp_1.default(path.dirname(globalPkgPath));
            yield writePkg(globalPkgPath, DefaultGlobalPkg);
            return DefaultGlobalPkg;
        }
    });
}
function resolveStoreBasePath(storePath, pkgRoot) {
    if (expandTilde_1.isHomepath(storePath)) {
        return expandTilde_1.default(storePath);
    }
    return path.resolve(pkgRoot, storePath);
}
function getStorePath(treeType, storeBasePath) {
    if (underNodeModules(storeBasePath)) {
        return storeBasePath;
    }
    // potentially shared stores have to have separate subdirs for different
    // installation types
    if (env_1.preserveSymlinks) {
        return path.join(storeBasePath, treeType);
    }
    return path.join(storeBasePath, `${treeType}-node.v4`);
}
function underNodeModules(dirpath) {
    return dirpath.split(path.sep).indexOf('node_modules') !== -1;
}
//# sourceMappingURL=getContext.js.map